home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / AHDI / TTDRIVER / DRIVER.TST < prev    next >
Encoding:
Text File  |  2001-02-09  |  67.8 KB  |  2,192 lines

  1. ; May 03 1991 v4.04b'
  2.  
  3. ;------------------------------------------------------------------------
  4. ;                                    :
  5. ;    AHDI Hard Disk Driver for the Atari ST and TT            :
  6. ;    Copyright 1985,1986,1987,1988,1989,1990,1991 Atari Corp.    :
  7. ;    All Rights Reserved                        :
  8. ;                                    :
  9. ;------------------------------------------------------------------------
  10.  
  11.  
  12. ;+
  13. ; Conditional Assembly Switches
  14. ;-
  15. ospool        equ    1        ; increase size of OS pool for ROM
  16.  
  17.  
  18. ;
  19. ;+
  20. ; Edit History
  21. ;
  22. ;
  23. ; 22-May-1989    ml    Started this from ahdi 3.00
  24. ;            Files created for this driver:
  25. ;            ACSI.S        Low-level driver for ACSI.
  26. ;            CMDBLK.S    Builds packets for command blocks.
  27. ;            DOIT.S        Sends packets out to SCSI or ACSI.
  28. ;            DRIVER.S    This file.
  29. ;            SCSI.S        Low-level driver for SCSI.
  30. ;
  31. ; 25-May-1989    ml    Eliminated pread(), use _ahdi_rw() in physical mode
  32. ;            instead.
  33. ;
  34. ; 06-Jun-1989    ml    Created INSTALL.S for driver installation.
  35. ;
  36. ; 11-Jul-1989    ml    Rwabs() now handles DMA to fast RAM on ACSI side
  37. ;            also.  If no extra RAM was reserved for fast RAM
  38. ;            transferred, _dskbufp is used for the transfer.
  39. ;            (This is going to be really slow!!!)
  40. ;
  41. ; 19-Jul-1989    ml    If there is cache on CPU, Rwabs() reads will
  42. ;            flush both the I and D cache.
  43. ;
  44. ; 06-Sept-1989    ml    Use _FRB (in the cookie jar) for fast RAM transfer,
  45. ;            assuming _FRB WILL be there if there is fast RAM on
  46. ;            the machine.
  47. ;
  48. ; 20-Feb-1990    ml 3.64    Fixed bug in return code when doing ACSI odd transfer.
  49. ;            When successful, 0 should be returned.
  50. ;
  51. ; 02-Mar-1990    ml 3.65    Took out wait loop for SCSI 0 to be ready.
  52. ;            (In install.s)
  53. ;
  54. ; 05-Mar-1990    ml 3.66    Added more checks for I/O to ACSI and SCSI non-
  55. ;            accessible memory.  _FRB will be used if it exists.
  56. ;            If _FRB doesn't exist, _dskbuf will used (which
  57. ;            means I/O could be "really" slow).  (_do_rw())
  58. ;
  59. ;            _FRB is being looked for when it's needed for the
  60. ;            first time, not at boot time.  (Applications can
  61. ;            add the _FRB when they are executed.)
  62. ;
  63. ; 08-Mar-1990    ml    Added SCFRDMA flag in defs.h to make SCSI DMA to 
  64. ;            fast RAM conditional assembly.
  65. ;            (driver.s modified)
  66. ;
  67. ; 15-Mar-1990    ml    Added DEBUG flag in defs.h to make debugging code
  68. ;            conditional assembly.
  69. ;
  70. ; 09-Apr-1990    ml 3.67    Added a "read" from WDL after toggling the ACSI DMA
  71. ;            chip to point the MMU to the correct direction.
  72. ;            (acsi.s modified)
  73. ;
  74. ; 10-Apr-1990    ml    Put up banner at beginning and end of loading driver
  75. ;            (requested by jwt), instead of just at the end.
  76. ;            (Printing of banner moved to install.s)
  77. ;
  78. ; 17-Apr-1990    ml    Added ODMA flag in defs.h to make the klutch of 
  79. ;            making byte counter bigger than # bytes requested
  80. ;            when receiving data from SCSI conditional assembly.
  81. ;            (scsi.s modified)
  82. ;
  83. ; 20-Apr-1990    ml    Added RDWDL flag in defs.h to make the "extra read"
  84. ;            added on 09-Apr-1990 conditional assembly.  (When
  85. ;            writing to ACSI, first 32 bytes are always FF's!!
  86. ;            Wondering why...)
  87. ;            (acsi.s modified)
  88. ;
  89. ; 30-Jul-1990    ml 4.00    Final for TT release. 
  90. ;            (Vectored-interrupts code not included)
  91. ;
  92. ; 31-Jul-1990    ml     Vectored-interrupt code included.
  93. ;
  94. ; 29-Oct-1990    ml 4.01    BUG!!!  Getcookie() module provided by AKP has a
  95. ;            variable declared in the bss.  This bss will be
  96. ;            clobbered when the driver adds GEMDOS buffers and
  97. ;            OS pool.  When getcookie() was called, and access 
  98. ;            the bss, it clobbered whatever was using its space
  99. ;            at the time.
  100. ;            Fixed in cookie.s by changing moving the variable
  101. ;            from the bss to the text segment.
  102. ;            (cookie.s modified)
  103. ;
  104. ; 26-Nov-1990    ml 4.02    BUG!!  From 3.00 through 4.01, when Rwabs() is called
  105. ;            in raw mode, it ignored media change completely.
  106. ;            This created problems with cartridge swapping on the 
  107. ;            removable drives.  If Getbpb(), on a logical drive 
  108. ;            that has not been accessed on the previous cartridge,
  109. ;            is called right after a cartridge swap, Getbpb() will
  110. ;            call Rwabs() in raw mode to read the partition map of
  111. ;            the physical unit concerned.  This Rwabs() call will
  112. ;            get the media change error from the controller and 
  113. ;            ignores it without setting any mcflg of the physical
  114. ;            unit.  Now when Mediach(), on a logical drive that was
  115. ;            accessed on the previous cartridge, is called, the 
  116. ;            driver will return media not change!
  117. ;            In version 4.02, Rwabs() still does not return media
  118. ;            change error when called in raw mode, but will 
  119. ;            remember it  by setting the mcflgs of the physical 
  120. ;            unit concerned to maybe changed.
  121. ;
  122. ; 02-Apr-1991    ml 4.03    BUG!!  At boot time, 
  123. ;                move.l    #(i_sasi1-i_sasi),tokeep 
  124. ;            is used to find number of bytes of code to keep.  
  125. ;            In pre-4.00 AHDI, this works just fine because both 
  126. ;            i_sasi1 and i_sasi are in the same file.  But, since 
  127. ;            3.00, i_sasi1 has been moved to the file INSTALL.S, 
  128. ;            thus external.  Madmac did not complain that the 
  129. ;            expression #(i_sasi1-i_sasi) is not valid anymore.  
  130. ;            Instead it assembles the code as
  131. ;                move.l    #i_sasi1,tokeep
  132. ;            This is bad, because it depends of where the driver 
  133. ;            is being loaded, the driver may end up hogging large
  134. ;            amount of memory that it is not using.  This is now
  135. ;            fixed by calculating the amount at run time.
  136. ;                move.l    #i_sasi1,tokeep 
  137. ;                subi.l    #i_sasi,tokeep
  138. ;            (driver.s modified)
  139. ;
  140. ; 04-Apr-1991    ml    Some SCSI drives will recalibrate every so often.
  141. ;            While recalibrating, the drive still accepts the
  142. ;            command block, but delays the transfer of data to 
  143. ;            after the recalibration.  So, timeout for the data
  144. ;            transfer should include the amount of time spent 
  145. ;            on recalibration.  The worst case we know of is
  146. ;            the Fujisu drives which takes 4 seconds.  So, the 
  147. ;            default for recalibration time is set to 4 seconds.
  148. ;            (driver.s, scsi.s modified)
  149. ;
  150. ; 10-Apr-1991  ml 4.04a    Added in implementation of Arbitration on SCSI bus.
  151. ;            (scsi.s modified)
  152. ;
  153. ; 01-May-1991  ml 4.04b    For testing purpose. (UNIX problem with MAXTOR).
  154. ;            (Conditional assembly: DBMAX flag in defs.h)
  155. ;            
  156. ;-
  157.  
  158.  
  159. .include    "defs.h"
  160. .include    "error.h"
  161. .include    "sysvar.h"
  162. .include    "68030.s"
  163. .include    "mfp.h"
  164. .include    "scsi.h"
  165.  
  166.  
  167. .extern _untrdy
  168. .extern _rqsense
  169. .extern _hread
  170. .extern _hwrite
  171. .extern _xtdread
  172. .extern _xtdwrt
  173.  
  174. .extern    i_sasi1
  175. .extern    _getcookie
  176.  
  177. ;
  178. ;+
  179. ; Entry points:
  180. ;
  181. ;    +0   GEMDOS entry point (double-click, or \AUTO folder on floppy)
  182. ;    +4   Boot entry point (from driver file off of C:)
  183. ;    +8   Reserved for future use
  184. ;    +$C  $F0AD magic number
  185. ;    +$E  version number
  186. ;    +$12 # chunks of ospool to add
  187. ;    +$14 # of sqnpart entries that follows
  188. ;    +$16 first sqnpart entry
  189. ;
  190. ; if bootloaded, d0 = # bytes allocated by boot code.
  191. ;-
  192. i_sasi:    bra    gboot            ; GEMDOS entry-point
  193.     bra    iboot            ; Boot entry-point
  194.     bra    iboot            ; (unused, reserved)
  195.  
  196.  
  197. ;+
  198. ;  Patchable variables
  199. ;-
  200. magicnum:    dc.w    $f0ad        ; wasn't here in previous releases
  201. vernum:        dc.w    $0404        ; version number
  202. numchunks:    dc.w    128        ; # chunks of ospool to add
  203.         .globl    defbigsect
  204. defbigsect:    dc.w    512        ; default size of a big sector
  205. numsqnpart:    dc.w    MAXACSI        ; number of sqnpart entries to follow
  206.         .globl    defsqnpart
  207. defsqnpart:    dcb.b    MAXACSI,1    ; default # drives for rmvbl ACSI unit
  208.  
  209. ; They're NEW!! Introduced in this version:
  210. numsqcnpart:    dc.w    MAXSCSI        ; number of sqcnpart entries to follow
  211.         .globl    defsqcnpart
  212. defsqcnpart:    dcb.b    MAXSCSI,1    ; default # drives for rmvbl SCSI unit
  213.         .globl    scxltmout    
  214. scxltmout:    dc.l    12001        ; SCSI long-timeout (>1 min)
  215.         .globl    slwsclto    
  216. slwsclto:    dc.l    5000        ; SCSI stunit() long-timeout (>25s)
  217.         .globl    slwscsto    
  218. slwscsto:    dc.l    42        ; SCSI stunit() short-timeout (>205ms)
  219.         .globl    scltmout    
  220. scltmout:    dc.l    201        ; SCSI long-timeout (>1000 ms)
  221.         .globl    scstmout    
  222. scstmout:    dc.l    101        ; SCSI short-timeout (>500 ms)
  223.         .globl    rcaltm    
  224. rcaltm:        dc.l    801        ; time for drive recalibration (>4s)
  225.         .globl    scsiid
  226. scsiid:        dc.b    6        ; SCSI host ID
  227. .even
  228.  
  229.  
  230. ;+
  231. ; GEMDOS entry;
  232. ;   find amount of memory availble and store in d0.l
  233. ;-
  234. gboot:    movea.l    4(sp),a2        ; a2 -> basepage
  235.     move.l    4(a2),d0        ; d0 = available memory
  236.     sub.l    (a2),d0            ;    = p_hitpa - p_lowtpa - basepage
  237.     sub.l    #$0100,d0
  238.     bra    i_sasi1            ; (continue with normal initialization)
  239.  
  240.  
  241. ;+
  242. ;  Boot entry;
  243. ;    set "bootloaded", record base address from boot loader, 
  244. ;    and continue with normal boot process.
  245. ;-
  246. iboot:    st    bootloaded        ; boot entry-point, set flag
  247.     sub.l    #$1c,d0            ; memory available -= file header
  248.     move.l    a2,baseaddr        ; install base address
  249.                     ; a2 = beginning addr of this block
  250.     bra    i_sasi1            ; (continue with normal initialization)
  251.  
  252.  
  253. ;
  254. ;+
  255. ; Driver State
  256. ;-
  257.         dc.b    13,'AHDI : May 03 1991 v4.04b'
  258.         dc.b    13,10,$bd,'Atari Corp.'
  259.         dc.b    ' 1985, 1986, 1987, 1988, 1989, 1990, 1991'
  260.         dc.b    13,10,0,$1A
  261. .even
  262.  
  263. ;*****  Beginning Of Published Variables  *****
  264.  
  265.         .globl    puns
  266. puns:        dc.w    0        ; # of physical units on user's system
  267.  
  268. dummy1:        dcb.b    2,-1        ; dummy pun entries for A and B
  269.         .globl    pun
  270. pun:        dcb.b    MAXUNITS,0    ; physical unit table
  271. .even
  272.  
  273. dummy2:        dcb.l    2,0        ; dummy start entries for A and B
  274.         .globl    start
  275. start:        dcb.l    MAXUNITS,0    ; partition start table
  276.  
  277.         .globl    cookie        ; *** DON'T CHANGE ***
  278. cookie:        dc.l    $41484449    ; cookie = 'AHDI'
  279.  
  280.         .globl    cookptr
  281. cookptr:    dc.l    0        ; pointer to cookie
  282.  
  283. versn:        dc.w    $0404        ; version number: MMmm
  284.  
  285.         .globl    maxssz
  286. maxssz:        dc.w    512        ; maximum sector size allowed
  287.  
  288. spndown:    dc.l    0        ; time limit to spin down unit 0
  289.                     ; applicable to Stacy ONLY
  290.  
  291.         .globl    numacsi
  292. numacsi:    dc.w    0        ; number of ACSI drives
  293.  
  294.         dcb.w    29,0        ; reserved for future use
  295.  
  296. ;*****  End Of Published Variables  *****
  297.  
  298.     .globl    mcflgs
  299. mcflgs:    dcb.b    MAXUNITS,2        ; media change flag table
  300.     .globl    xst
  301. xst:    dcb.b    MAXUNITS,1        ; drive existence flag table
  302. bpbs:    dcb.b    BPBLEN,0        ; a bpb 
  303. serno:    dcb.b    MAXUNITS*SERLEN,0    ; serial number table
  304.     .globl    sratio
  305. sratio:    dcb.b    MAXUNITS,1        ; log sect size : phys sect size tbl
  306. fatsum:    dcb.b    MAXUNITS*FATLEN,0    ; FAT checksum table
  307. fatst:    dcb.w    MAXUNITS,0        ; starting sector # of last FAT
  308. fatend:    dcb.w    MAXUNITS,0        ; ending sector # of last FAT
  309.  
  310.         .globl    bootloaded
  311. bootloaded:    dc.w    0        ; nonzero if loaded from boot sector
  312.         .globl    memalloc
  313. memalloc:    dc.l    0        ; total memory available if bootloaded
  314. baseaddr:    dc.l    0        ; -> base addr of .PRG file
  315. tokeep:        dc.l    0        ; amount memory to keep
  316.  
  317.         .globl    cpun
  318. cpun:        dc.w    0        ; current physical unit
  319.         .globl    npart
  320. npart:        dc.w    0        ; number of partitions found
  321. bfat:        dc.w    0        ; 0: 12-bit FAT; 1: 16-bit FAT
  322.  
  323. strec:        dc.l    0        ; starting sector to read/write
  324. endrec:        dc.l    0        ; last sector to read/write
  325. stbuf:        dc.l    0        ; starting address of buffer
  326.         .globl    embscsi
  327. embscsi:    dc.b    0        ; 1: embedded SCSI drive
  328.  
  329. frbbuf:        dc.l    0        ; pointer to _FRB
  330.  
  331. _retries:    dc.w    NRETRIES    ; number of retries to do
  332. retrycnt:    dc.w    1        ; retry counter
  333.  
  334.         .globl    o_bpb
  335. o_bpb:        dc.l    1        ; old bpb vector
  336.         .globl    o_rw
  337. o_rw:        dc.l    1        ; old rwabs vector
  338.         .globl    o_mediach
  339. o_mediach:    dc.l    1        ; old media change vector
  340.  
  341.         .globl    sendata
  342. sendata:    dcb.b    32,0        ; buffer for sense data
  343.  
  344. lastmdctm:    dc.l    0        ; time media change was last called
  345.         .globl    pbuf
  346. pbuf:        dc.l    0        ; ptr to start of root sector image
  347. fsiz:        dc.w    0        ; FAT size in sectors
  348. fatrec:        dc.w    0        ; 2nd FAT starting sector
  349.         .globl    sizr
  350. sizr:        dc.w    1        ; ratio of log : phys sector size
  351. cstart:        dc.l    0        ; current dev's starting sector
  352. temp:        dc.l    0        ; temporary storage
  353.         .globl    savssp
  354. savssp:        dc.l    1        ; (saved SSP)
  355.         .globl    _cachexst
  356. _cachexst:    dc.b    0        ; 0: no cache    1: with cache
  357.         .globl    ext
  358. ext:        dc.b    0        ; if =0, not processing ext partition
  359.         .globl    extrt
  360. extrt:        dc.l    0        ; starting sector of ext DOS partition
  361.         .globl    extvol
  362. extvol:        dc.l    0        ; offset wrt ext DOS partition
  363. pbpb:        dc.w    0        ; partition # for dev
  364. .even
  365.  
  366.  
  367. ;
  368. ;+
  369. ; Front End
  370. ;-
  371.  
  372. ;+
  373. ;  Return pointer to BPB (or NULL)
  374. ;
  375. ;    Synopsis:    LONG hbpb(dev)
  376. ;        WORD dev;    4(sp).w
  377. ;-
  378.     .globl    hbpb
  379. hbpb:    move.w    4(sp),d0        ; d0 = devno
  380.     clr    d1            ; d1 = 0, physical op not possible
  381.     movea.l    o_bpb,a0        ; a0 -> pass-through vector
  382.     lea    _sasi_bpb(pc),a1    ; a1 -> our handler
  383.     bra.s    check_dev        ; do it
  384.  
  385.  
  386. ;+
  387. ;  Read or write logical sectors
  388. ;
  389. ;    Synopsis:    LONG hrw(rw, buf, count, recno, dev)
  390. ;        WORD rw;    $4(sp).w
  391. ;        char *buf;    $6(sp).l
  392. ;        WORD count;    $a(sp).w
  393. ;        WORD recno;    $c(sp).w
  394. ;        WORD dev;    $e(sp).w
  395. ;-
  396.     .globl    hrw
  397. hrw:    move.w    $e(sp),d0        ; d0 = devno
  398.     move.w    4(sp),d1        ; d1 includes physical device flag
  399.     movea.l    o_rw,a0            ; a0 -> pass-through vector
  400.     lea    _sasi_rw(pc),a1        ; a1 -> our handler
  401.     bra.s    check_dev        ; do it
  402.  
  403.  
  404. ;+
  405. ;  Check for media change
  406. ;
  407. ;    Synopsis:    LONG hmediach(dev)
  408. ;        WORD dev;    4(sp).w
  409. ;-
  410.     .globl    hmediach
  411. hmediach:
  412.     move.w    4(sp),d0        ; d0 = devno
  413.     clr    d1            ; physical operation not possible
  414.     movea.l    o_mediach,a0        ; a0 -> pass-through vector
  415.     lea    _sasi_mediach(pc),a1    ; a1 -> our handler
  416.  
  417.  
  418. ;+
  419. ;  check_dev - use handler, or pass vector through
  420. ;
  421. ;  Passed:    d0.w = device#
  422. ;        d1, bit 3  1=physical operation
  423. ;        a0 ->  old handler
  424. ;        a1 ->  new handler
  425. ;        a5 ->  $0000 (zero-page ptr)
  426. ;
  427. ;  Jumps-to:    (a1) if dev in range for this handler
  428. ;        (a0) otherwise
  429. ;-
  430. check_dev:
  431.     subq    #2,d0            ; lowest device is 2 (unit 0 or C:)
  432.     bmi.s    chkd_f            ; if lower, not one of ours
  433.  
  434.     btst    #3,d1            ; is this a physical unit operation?
  435.     beq.s    chkd_a            ; if not set, go to chkd_a
  436.  
  437.     cmp.w    numacsi,d0        ; a valid ACSI unit?
  438.     blt.s    chkd_s            ; if so, it's one of ours
  439.  
  440.     sub.w    #MAXACSI,d0        ; a SCSI unit number?
  441.     bmi.s    chkd_f            ; if lower, not one of ours
  442.  
  443.     move.w    puns,d1            ; d1.w = number of valid SCSI units
  444.     sub.w    numacsi,d1        ;      = total num - num ACSI
  445.     cmp.w    d1,d0            ; a valid SCSI unit?
  446.     bge.s    chkd_f            ; if higher, not one of ours
  447.     bra.s    chkd_s            ; else it IS one of of ours
  448.  
  449. chkd_a:    
  450.  
  451. ;+
  452. ; Aug-08-91 ml.    Added upper bound check for logical device #
  453. ;
  454.     cmp.w    #MAXUNITS,d0        ; if logical device # >= MAXUNITS
  455.     bge.s    chkd_f            ; it's not one of ours
  456. ;-
  457.     lea    pun,a2            ; pointer to pun map
  458.     tst.b    0(a2,d0.w)        ; must be positive for a real unit
  459.     bmi.s    chkd_f
  460. chkd_s:    movea.l    a1,a0            ; yes -- follow success vector
  461. chkd_f:    jmp    (a0)            ; do it
  462.  
  463.  
  464. ;
  465. ;+
  466. ; Medium-Level Driver
  467. ;-
  468.  
  469. ;+
  470. ; Return BPB for logical device
  471. ;
  472. ; Synopsis:    LONG _sasi_bpb(dev)
  473. ;        WORD dev;    $4(sp).w
  474. ;
  475. ; Returns:    NULL, or a pointer to the BPB buffer
  476. ;
  477. ; 10-21-88    ml.    I am not making a special case for non-removable
  478. ;            hard disk, because if a program uses Allan's
  479. ;            program to force a media change, the program 
  480. ;            should be getting the "Real" AND "New" BPB.
  481. ;            (The old (v1.7 and before) AHDI only index into
  482. ;            the bpbs table and return the pointer, without
  483. ;            actually go and read the boot sector of the dev.)
  484. ;-
  485. _sasi_bpb:
  486.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  487.     move.w    4(sp),d1        ; d1 = device number
  488.     lea    pun,a0            ; a0 -> pun table
  489.     adda.w    d1,a0            ; a0 -> pun @ dev's entry
  490.     moveq    #0,d2            ; coerce byte to word
  491.     move.b    (a0),d2            ; d2.w = pun that dev belongs to
  492.     move.w    d2,cpun            ; cpun = pun(dev)
  493.  
  494.     lea    xst,a1            ; a1 -> drive existence table
  495.     tst.b    (a1,d1.w)        ; does drive exist?
  496.     bne.s    bpbgo            ; if it does, go on normally
  497.                     ; else, see if it really doesn't exist
  498.     movem.l    d1/a0,-(sp)        ; save registers
  499.     move.w    d2,-(sp)        ; physical unit number
  500.     bsr    _untrdy            ; verify by doing test unit ready
  501.     addq.l    #2,sp            ; cleanup stack
  502.     movem.l    (sp)+,d1/a0        ; restore registers
  503.     tst.w    d0            ; return good status?
  504.     beq    badbpb            ; if yes, ie. medium has not changed
  505.                     ; therefore, dev still doesn't exist
  506.     moveq    #1,d0            ; else medium may have changed
  507.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  508.                     ; and go try to get BPB
  509. bpbgo:    move.l    _dskbufp,pbuf        ; pbuf -> 2nd half of 1K disk buf
  510.     add.l    #512,pbuf
  511.  
  512. bpb00:    move.l    a0,-(sp)        ; save ptr to pun(dev)
  513.     move.w    cpun,-(sp)        ; physical unit number
  514.     addq.w    #2,(sp)            ; unit # including A: and B:
  515.     clr.w    -(sp)            ; from sector 0
  516.     move.w    #1,-(sp)        ; read in 1 sector
  517.     move.l    pbuf,-(sp)        ; buffer to read into
  518.     move.w    #$a,-(sp)        ; in phys mode/ignore media change
  519.     bsr    _ahdi_rw        ; ahdi_rw($a, pbuf, 1, 0, cpun)
  520.     adda    #12,sp
  521.     movea.l    (sp)+,a0        ; restore ptr to pun(dev)
  522.     tst    d0            ; read successful?
  523.     beq.s    bpb0            ; if yes, go on normally
  524.                     ; else call up error handler
  525. bpberr:    move.l    a0,-(sp)        ; save ptr to pun(dev)
  526.     move.w    8(sp),d1        ; a0 = drive # excluding A: and B:
  527.     bsr    critic            ; call up critical error handler
  528.     move.l    (sp)+,a0        ; restore ptr to pun(dev)
  529.     cmpi.l    #CRITRETRY,d0        ; retry?
  530.     beq.s    bpb00            ; if so, go and try again
  531.     bra    badbpb            ; else return no BPB
  532.  
  533. bpb0:    move.w    cpun,d2            ; d2 = physical unit number of dev
  534.     move.w    #0,pbpb            ; pbpb = partition # dev corresponds
  535. bpb1:    cmp.b    -(a0),d2        ; pun that dev belongs to == (a0)?
  536.     bne.s    bpb2
  537.     addq.w    #1,pbpb
  538.     bra.s    bpb1
  539.  
  540. bpb2:    move.w    #MAXNPART,d1        ; do #MAXNPART times
  541.     movea.l    pbuf,a0            ; a0 -> beginning of root sector
  542.     cmpi.w    #SIG,DOSSIG(a0)        ; is root sector in DOS format?
  543.     bne.s    bpb3            ; if not, assume it's in GEMDOS format
  544.     bsr    dosbpb            ; else, handle it the DOS way
  545.     bra.s    bpb4            ; else, go get the bpb
  546. bpb3:    move.w    #1,bfat            ; 16 bit FAT always for GEMDOS
  547.     bsr    gembpb            ; handle it the GEMDOS way
  548. bpb4:    tst.w    d0            ; successful?
  549.     beq.s    bpbnf            ; if =0, no valid BPB found
  550.     bpl.s    bpb5            ; if +ive, valid BPB found
  551.     bra.s    badbpb            ; else no BPB found
  552.                     ; partition not found
  553. bpbnf:    lea    xst,a0            ; a0 -> drive existence table
  554.     move.w    4(sp),d0        ; d0 = dev number
  555.     clr.b    (a0,d0.w)        ; dev definitely does not exist
  556.     lea    mcflgs,a0        ; a0 -> mcflgs table
  557.     move.b    #2,(a0,d0.w)        ; set as medium has changed
  558.     bra.s    badbpb            ; can't find such a partition
  559.  
  560. bpb5:    move.l    d1,-(sp)        ; start_sector
  561.     move.w    8(sp),-(sp)        ; dev number
  562.     bsr    getbpb            ; getbpb(dev, start_sector)
  563.     addq.l    #6,sp            ; clean up stack
  564.     tst.l    d0            ; getbpb successful?
  565.     bpl.s    retbpb            ; if so, return ptr to bpb
  566. badbpb:    moveq    #0,d0            ; return no bpb found
  567. retbpb:    rts
  568.  
  569.  
  570. ;
  571. ;+
  572. ; dosbpb - find the DOS partition that corresponds to the requested
  573. ;       logical drive
  574. ; Passed:
  575. ;    a0 = buffer address for root sector
  576. ;    d1 = number of entries in partition map
  577. ;
  578. ; Assumed:
  579. ;    pbpbs = partition being looked for
  580. ;
  581. ; Returns:
  582. ;    d0.b = 0        if partition not found
  583. ;         = negative #    some kind of error
  584. ;         = positive #    system indicator of the partition
  585. ;    d1.l = starting sector of the partition (if it is found)
  586. ;-
  587. dosbpb:    adda.w    #DOSPM,a0        ; a0 -> partition map
  588. dbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  589.     sf    ext            ; not dealing with ext partition
  590.     bsr    fdpart            ; find a partition
  591.     tst.b    d0            ; found any?
  592.     beq.s    dbpba            ; not a valid partition
  593.     cmpi.b    #5,d0            ; extended partition?
  594.     bne.s    dbpb1            ; if not, it's a regular partition
  595.     st    ext            ; else, it's an extended partition
  596.     move.l    #0,extvol        ; offset from start of partition = 0
  597.     move.l    d1,extrt        ; starting sector # of ext partition
  598. dbpbx:    bsr    fdnxt            ; find next logical drive
  599.     tst.b    d0            ; found any?
  600.     beq.s    dbpba            ; no logical drive found
  601.     bmi.s    dbpb2            ; error returned
  602.     cmpi.b    #5,d0            ; extended volume?
  603.     beq.s    dbpbx            ; if so, go find next logical drive
  604. dbpb1:    subq.w    #1,pbpb            ; partition that we want?
  605.     bpl.s    dbpb3            ; if not, continue the search
  606. dbpb2:    addq.l    #8,sp            ; else clean up stack
  607.     move.w    #0,bfat            ; assume partition has 12-bit fat
  608.     cmpi.b    #1,d0            ; 12-bit fat?
  609.     beq.s    dbpb22            ; if so, return
  610.     move.w    #1,bfat            ; else bflag = 1 for 16-bit fat
  611. dbpb22:    bra.s    dbpbr            ; and return
  612. dbpb3:    tst.b    ext            ; clun is in ext partition?
  613.     bne.s    dbpbx            ; if so, go find next ext vol
  614. dbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  615.     adda    #16,a0            ; index to next entry in pmap
  616.     dbra    d1,dbpb0
  617.     moveq    #0,d0            ; partition not found!
  618. dbpbr:    rts
  619.  
  620.     
  621. ;+
  622. ; fdpart - find a DOS partition.
  623. ;
  624. ; Passed:
  625. ;    a0 = address to partition entry
  626. ;
  627. ; Returns:
  628. ;    d0.b = 0        partition is not valid
  629. ;         = positive    #    partition is a valid partition
  630. ;           (this is the system indicator of the partition)
  631. ;    d1.l = starting sector # of a valid partition (if d0.b = 1 or 4)
  632. ;         = starting sector # of extended partition (if d0.b = 5)
  633. ;-
  634.     .globl    fdpart
  635. fdpart:    tst.l    12(a0)            ; partition's size?
  636.     beq.s    fdp0            ; if =0, not valid
  637.  
  638.     move.b    4(a0),d0        ; d0 = system indicator
  639.     beq.s    fdpr            ; if =0, not valid
  640.  
  641.     cmpi.b    #4,d0            ; if =4, valid
  642.     beq.s    fdp1
  643.  
  644.     cmpi.b    #1,d0            ; if =1, valid
  645.     beq.s    fdp1
  646.  
  647.     cmpi.b    #5,d0            ; if =5, valid
  648.     beq.s    fdp1
  649.  
  650. fdp0:    moveq    #0,d0            ; else, not valid
  651.     bra.s    fdpr
  652.  
  653. fdp1:    move.l    8(a0),d1        ; d1.l = swapped starting sector #
  654.     ror.w    #8,d1            ; swap hi and lo byte of high word
  655.     swap    d1            ; swap hi and lo word
  656.     ror.w    #8,d1            ; swap hi and lo byte of low word
  657. fdpr:    rts
  658.  
  659.  
  660. ;+
  661. ; fdnxt - find a logical drive in the extended DOS partition
  662. ;
  663. ; Passed:
  664. ;    d0.b = (= 5 if a new extended volume was found)
  665. ;           (= 0 if nxtdrv was successful for last logical drive found)
  666. ;    d1.l = starting sector # of this extended volume
  667. ;    d2.b = count down for logical drive entries (if d0.b != 5)
  668. ;    a0.l = address of partition entry to be checked (if d0.b != 5)
  669. ;
  670. ; Assumes:
  671. ;    cpun = current physical unit #
  672. ;    extrt = starting sector # of extended DOS partition
  673. ;    extvol = offset from start of extended DOS partition (in sectors)
  674. ;
  675. ; Returns:
  676. ;    d0.b = 0        no logical drive found
  677. ;         = positive #    valid logical drive found
  678. ;           (this is the system indicator of the logical drive)
  679. ;         = negative #    error occured
  680. ;    d1.l = starting sector # of the logical drive (if d0.b = 1 or 4)
  681. ;         = starting sector # of next extended volume (if d0.b = 5)
  682. ;-
  683.     .globl    fdnxt
  684. fdnxt:    cmpi.b    #5,d0        ; new extended volume found?
  685.     bne.s    fdnxt0        ; if not, search for one
  686.     move.l    d1,-(sp)    ; from beginning of extended volume
  687.     move.w    cpun,-(sp)    ; physical unit number
  688.     addq.w    #2,(sp)        ; unit # including A: and B:
  689.     move.w    #-1,-(sp)    ; using a long sector number
  690.     move.w    #1,-(sp)    ; read in 1 sector
  691.     move.l    _dskbufp,-(sp)    ; buffer to read into
  692.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  693.     bsr    _ahdi_rw    ; ahdi_rw($a, buf, 1, -1, cpun, lsectno)
  694.     adda    #16,sp        ; cleanup stack
  695.     tst.w    d0        ; read successful?
  696.     bne    fdnxtr        ; if not, return
  697.     
  698.     movea.l    _dskbufp,a0    ; else, 
  699.     cmpi.w    #SIG,DOSSIG(a0)    ; boot record valid?
  700.     bne.s    fdnxtr        ; if not, return no drive found
  701.                 ; (d0 already set by ahdi_rw)
  702.     adda.w    #DOSPM-16,a0    ; a0 -> 1st entry in log drive map
  703.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  704.  
  705. fdnxt0:    subq.w    #1,d2        ; more entries to search?
  706.     bmi.s    fdnxt1        ; if not, return
  707.  
  708.     adda    #16,a0        ; a0 -> entry to be examined
  709.     tst.l    12(a0)        ; partition size's?
  710.     beq.s    fdnxt0        ; if =0, not valid
  711.  
  712.     move.b    4(a0),d0    ; d0 = system indicator
  713.     beq.s    fdnxt0        ; if =0, not valid
  714.  
  715.     move.l    8(a0),d1    ; d1.l = logical start sector of drv or vol
  716.     beq.s    fdnxt0        ; if =0, not valid
  717.     ror.w    #8,d1        ; swap hi and lo byte of high word
  718.     swap    d1        ; swap hi and lo word
  719.     ror.w    #8,d1        ; swap hi and lo byte of low word
  720.  
  721.     cmpi.b    #4,d0        ; if =4,
  722.     beq.s    fdnxt2        ; valid logical drive found
  723.  
  724.     cmpi.b    #1,d0        ; if =1,
  725.     beq.s    fdnxt2        ; valid logical drive found
  726.  
  727.     cmpi.b    #5,d0        ; if =5, valid ptr to next ext volume
  728.     bne.s    fdnxt0        ; else, not valid
  729.     move.l    d1, extvol    ; offset of ext vol from start of ext DOS
  730.     bra.s    fdnxt3
  731.  
  732. fdnxt1:    moveq    #0,d0        ; return no drive found
  733.     bra.s    fdnxtr
  734.  
  735. fdnxt2:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  736. fdnxt3:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  737. fdnxtr:    rts
  738.  
  739.  
  740. ;
  741. ;+
  742. ; gembpb - find the GEMDOS partition that corresponds to the requested
  743. ;       logical drive.
  744. ; Passed:
  745. ;    a0 = buffer address for root sector
  746. ;    d1 = number of entries in partition map
  747. ;
  748. ; Assumed:
  749. ;    pbpbs = partition being looked for
  750. ;
  751. ; Returns:
  752. ;    d0.b = 0        if partition not found
  753. ;         = negative #    some kind of error
  754. ;         = positive #    system indicator of the partition
  755. ;    d1.l = starting sector of the partition (if it is found)
  756. ;-
  757. gembpb:    adda.w    #HDSIZ,a0        ; a0 -> hard disk size
  758.     tst.l    (a0)+            ; size? (a0 -> start of pmap)
  759.     beq.s    gbpb4            ; if =0, no drive will exist
  760. gbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  761.     sf    ext            ; not dealing with ext partition
  762.     bsr    fgpart            ; find partitions
  763.     tst.b    d0            ; found any?
  764.     beq.s    gbpba            ; not a valid partition
  765.     cmpi.b    #'X',d0            ; extended partition?
  766.     bne.s    gbpb1            ; if not, it's a regular partition
  767.     st    ext            ; else, it's an extended partition
  768.     move.l    #0,extvol        ; offset from start of partition = 0
  769.     move.l    d1,extrt        ; starting sector # of ext partition
  770. gbpbx:    bsr    fgnxt            ; find next logical drive
  771.     tst.b    d0            ; found any?
  772.     beq.s    gbpba            ; no logical drive found
  773.     bmi.s    gbpb2            ; error returned
  774.     cmpi.b    #'X',d0            ; extended volume?
  775.     beq.s    gbpbx            ; if so, go find next logical drive
  776. gbpb1:    subq.w    #1,pbpb            ; partition that we want?
  777.     bpl.s    gbpb3            ; if not, continue the search
  778. gbpb2:    addq.l    #8,sp            ; else BINGO!  Clean up stack
  779.     bra.s    gbpbr            ; and return
  780. gbpb3:    tst.b    ext            ; clun is in ext partition?
  781.     bne.s    gbpbx            ; if so, go find next ext vol
  782. gbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  783.     adda    #12,a0            ; index to next entry in pmap
  784.     dbra    d1,gbpb0
  785. gbpb4:    moveq    #0,d0            ; partition not found!
  786. gbpbr:    rts
  787.  
  788.  
  789. ;+
  790. ; fgpart - find a GEMDOS partition.
  791. ;
  792. ; Passed:
  793. ;    a0 = address to partition entry
  794. ;
  795. ; Returns:
  796. ;    d0.b = 0        partition is not valid
  797. ;         = positive    #    partition is a valid partition
  798. ;           (this is the first byte in p_id of the partition)
  799. ;    d1.l = starting sector # of a valid partition (if d0.b = 'G' or 'B')
  800. ;         = starting sector # of extended partition (if d0.b = 'X')
  801. ;-
  802.     .globl    fgpart
  803. fgpart:    tst.b    (a0)            ; check the valid partition flag
  804.     beq.s    fgp2            ; if =0, not valid
  805.  
  806.     tst.l    8(a0)            ; partition's size?
  807.     beq.s    fgp2            ; if =0, not valid
  808.  
  809.     cmpi.b    #'G',1(a0)        ; must find GEM as type
  810.     bne.s    fgp0            ; for REGULAR partition
  811.     cmpi.b    #'E',2(a0)        ; (ie., partition < 16Mb)
  812.     bne.s    fgp0
  813.     cmpi.b    #'M',3(a0)
  814.     beq.s    fgp3
  815.  
  816. fgp0:    cmpi.b    #'B',1(a0)        ; must find BGM as type
  817.     bne.s    fgp1            ; for BIG partition
  818.     cmpi.b    #'G',2(a0)        ; (ie., partition >= 16Mb)
  819.     bne.s    fgp1
  820.     cmpi.b    #'M',3(a0)
  821.     beq.s    fgp3
  822.  
  823. fgp1:    cmpi.b    #'X',1(a0)        ; or find XGM as type
  824.     bne.s    fgp2            ; for EXTENDED GEMDOS 
  825.     cmpi.b    #'G',2(a0)        ; partition
  826.     bne.s    fgp2            ; (ie., partition with
  827.     cmpi.b    #'M',3(a0)        ;  a linked list of
  828.     beq.s    fgp3            ;  logical drives)
  829.  
  830. fgp2:    moveq    #0,d0            ; else, not valid
  831.     bra.s    fgpr
  832.  
  833. fgp3:    move.l    4(a0),d1        ; d1.l = starting sector #
  834.     move.b    1(a0),d0        ; d0.b = first byte of p_id
  835. fgpr:    rts
  836.  
  837.  
  838. ;+
  839. ; fgnxt - find a logical drive in the extended GEMDOS partition
  840. ;
  841. ; Passed:
  842. ;    d0.b = (= 'X' if a new extended volume was found)
  843. ;           (= 0 if nxtdrv was successful for last logical drive found)
  844. ;    d1.l = starting sector # of this extended volume
  845. ;    d2.b = count down for logical drive entries (if d0.b != 'X')
  846. ;    a0.l = address of partition entry to be checked (if d0.b != 'X')
  847. ;
  848. ; Assumes:
  849. ;    cpun = current physical unit #
  850. ;    extrt = starting sector # of extended GEMDOS partition
  851. ;    extvol = offset from start of extended GEMDOS partition (in sectors)
  852. ;
  853. ; Returns:
  854. ;    d0.b = 0        no logical drive found
  855. ;         = positive #    valid logical drive found
  856. ;           (this is the first byte of p_id of the logical drive)
  857. ;         = negative #    error occured
  858. ;    d1.l = starting sector # of the logical drive (if d0.b = 'G' or 'B')
  859. ;         = starting sector # of next extended volume (if d0.b = 'X')
  860. ;-
  861.     .globl    fgnxt
  862. fgnxt:    cmpi.b    #'X',d0        ; new extended volume found?
  863.     bne.s    fgnxt0        ; if not, search for one
  864.     move.l    d1,-(sp)    ; from beginning of extended volume
  865.     move.w    cpun,-(sp)    ; physical unit number
  866.     addq.w    #2,(sp)        ; unit # including A: and B:
  867.     move.w    #-1,-(sp)    ; using a long sector number
  868.     move.w    #1,-(sp)    ; read in 1 sector
  869.     move.l    _dskbufp,-(sp)    ; buffer to read into
  870.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  871.     bsr    _ahdi_rw    ; ahdi_rw($a, buf, 1, -1, cpun, lsectno)
  872.     adda    #16,sp        ; cleanup stack
  873.     tst.w    d0        ; read successful?
  874.     bne    fgnxtr        ; if not, return error
  875.  
  876.     movea.l    _dskbufp,a0    ; a0 -> partition map
  877.     adda.w    #HDSIZ+4-12,a0    ; a0 -> 1st entry in log drive map
  878.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  879.  
  880. fgnxt0:    subq.w    #1,d2        ; more entries to search?
  881.     bmi.s    fgnxt3        ; if not, return
  882.  
  883.     adda    #12,a0        ; a0 -> entry to be examined
  884.     tst.l    8(a0)        ; partition size's?
  885.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  886.  
  887.     tst.b    (a0)        ; check the valid partition flag
  888.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  889.  
  890.     move.l    4(a0),d1    ; d1.l = logical start sector of drv or vol
  891.  
  892.     cmpi.b    #'G',1(a0)    ; must find GEM as type
  893.     bne.s    fgnxt1        ; for REGULAR partition
  894.     cmpi.b    #'E',2(a0)    ; (ie., partition < 16Mb)
  895.     bne.s    fgnxt1
  896.     cmpi.b    #'M',3(a0)
  897.     beq.s    fgnxt4
  898.  
  899. fgnxt1:    cmpi.b    #'B',1(a0)    ; must find BGM as type
  900.     bne.s    fgnxt2        ; for BIG partition
  901.     cmpi.b    #'G',2(a0)    ; (ie., partition >= 16Mb)
  902.     bne.s    fgnxt2
  903.     cmpi.b    #'M',3(a0)
  904.     beq.s    fgnxt4
  905.  
  906. fgnxt2:    cmpi.b    #'X',1(a0)    ; or find XGM as type
  907.     bne.s    fgnxt3        ; for EXTENDED GEMDOS 
  908.     cmpi.b    #'G',2(a0)    ; partition
  909.     bne.s    fgnxt3        ; (ie., partition with
  910.     cmpi.b    #'M',3(a0)    ;  a linked list of
  911.     bne.s    fgnxt0        ;  logical drives)
  912.  
  913.     move.l    d1, extvol    ; offset of ext vol from start of ext GEMDOS
  914.     bra.s    fgnxt5
  915.  
  916. fgnxt3:    moveq    #0,d0        ; return no drive found
  917.     bra.s    fgnxtr
  918.  
  919. fgnxt4:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  920. fgnxt5:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  921.     move.b    1(a0),d0    ; d0.b = first byte of p_id
  922. fgnxtr:    rts
  923.  
  924.  
  925. ;
  926. ;+
  927. ; getbpb(dev, sectorno)
  928. ; WORD dev;        4(sp).w
  929. ; LONG sectorno;    6(sp).l
  930. ;
  931. ; Assume -
  932. ;    cpun contains physical unit number of dev
  933. ;-
  934. getbpb:    move.l    $6(sp),-(sp)    ; sector # of boot sector
  935.     move.w    cpun,-(sp)    ; physical unit
  936.     addq.w    #2,(sp)        ; unit # including A: and B:
  937.     move.w    #-1,-(sp)    ; using a long sector number
  938.     move.w    #1,-(sp)    ; 1 sector
  939.     move.l    _dskbufp,-(sp)    ; buffer
  940.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  941.     bsr    _ahdi_rw    ; ahdi_rw(8, buf, 1, -1, cpun, lsectno)
  942.     adda    #16,sp        ; clean up stack
  943.     tst.w    d0        ; successful?
  944.     beq.s    getb0        ; if so, go on normally
  945.                 ; else let user retry
  946. getb9:    move.w    4(sp),d1    ; d1 = drive # excluding A: and B:
  947.     bsr    critic
  948.     cmpi.l    #CRITRETRY,d0    ; retry?
  949.     bne    getb7        ; if not, return
  950.     bra.s    getbpb        ; else read again
  951.  
  952. getb0:    movea.l    _dskbufp,a0    ; a0 -> boot sector image
  953.     movea.l    #bpbs,a2    ; a2 -> bpb
  954.  
  955.     move.w    #$0b,d0
  956.     bsr    getlhw
  957.     cmp.w    maxssz,d0    ; is sector size too big?
  958.     bhi    getb7        ; if it is, can't handle it
  959.     move.w    d0,(a2)+    ; =byt/sec
  960.     beq    getb7        ; if =0, bad data
  961.     move.w    d0,d1
  962.     divu    #512,d0        ; d0.b = ratio log : phys sector size
  963.     move.w    d0,sizr        ; save the ratio
  964.  
  965.     clr.w    d0
  966.     move.b    $d(a0),d0
  967.     move.w    d0,(a2)+    ; = #sectors/cluster
  968.     beq    getb7        ; if =0, bad data
  969.  
  970.     mulu    d1,d0
  971.     move    d0,(a2)+    ; = #bytes/cluster
  972.  
  973.     move    #$11,d0
  974.     bsr    getlhw        ; number of directory entries
  975.     tst    d0        ; num o' entries ?= 0
  976.     beq    getb7        ; if so, bad data
  977.      mulu    #32,d0        ; size of each entry
  978.     divu    d1,d0        ; number of sectors required
  979.     move.l    d0,d1
  980.     swap    d1
  981.     tst    d1
  982.     beq.s    getb1
  983.     addq    #1,d0        ; round up
  984. getb1:    move    d0,(a2)+    ; =rdlen
  985.     move    d0,d2
  986.  
  987.     move    #$16,d0
  988.     bsr    getlhw
  989.     move    d0,(a2)+    ; =FATsize
  990.     beq    getb7        ; if =0, bad data
  991.     move    d0,d1
  992.     move    d0,fsiz        ; save FAT size
  993.  
  994.     move    #$e,d0
  995.     bsr    getlhw        ; number of reserved sectors
  996.     add    d1,d0
  997.     move    d0,(a2)+    ; =2nd FAT start
  998.     move    d0,fatrec    ; save 2nd FAT start 
  999.  
  1000.     add    d1,d0        ; plus size of second fat
  1001.     add    d2,d0        ; plus rdlen
  1002.     move    d0,(a2)+    ; = data start
  1003.     move    d0,d2        ; save start of data
  1004.  
  1005.     move    #$13,d0
  1006.     bsr    getlhw        ; number of sectors on media
  1007.     sub    d2,d0        ; subtract # used by FATs,dir,boot
  1008.     beq    getb7        ; if =0, bad data
  1009.     clr.l    d1
  1010.     move    d0,d1
  1011.     clr    d0
  1012.     move.b    $d(a0),d0    ; number of sectors/cluster
  1013.     divu    d0,d1        ; rounding down
  1014.     move    d1,(a2)+    ; =number of clusters
  1015.     move    bfat,(a2)    ; =flags, 12 or 16 bit fats
  1016.  
  1017.     move.w    sizr,d2        ; d2 = current sector size ratio
  1018.     lea    sratio,a1    ; a1 -> sector size ratio table
  1019.     move.w    4(sp),d0    ; d0 = drive number
  1020.     move.b    d2,(a1,d0.w)    ; update sector size ratio in table
  1021.  
  1022.     btst.b    #6,cpun+1    ; is unit removable?
  1023.     beq    getb6        ; if not, can skip the fat checksum
  1024.  
  1025.     lea    serno,a1    ; a1 -> table of serial #s
  1026.     mulu.w    #SERLEN,d0    ; dev# * SERLEN to index into table
  1027.     adda.l    d0,a1        ; a1 -> serial # of dev
  1028.     move.w    #SERLEN-1,d1    ; length of serial # - 1
  1029. getb2:    move.b    $8(a0,d1.w),(a1,d1.w)    ; update serial # of dev
  1030.     dbra    d1,getb2
  1031.  
  1032.     lea    fatsum,a2    ; a2 -> FAT check sum table
  1033.     move.w    4(sp),d0    ; d0 = dev number
  1034.     mulu    #FATLEN,d0    ; d0*FATLEN = to index into table
  1035.     adda.l    d0,a2        ; a2 -> FAT check sum tbl of dev
  1036.  
  1037.     move.w    fatrec,d0    ; d0 = log starting sector of 2nd FAT
  1038.     mulu    d2,d0        ; (in 512-byte sectors)
  1039.     movea.l    $6(sp),a1    ; a1 = starting sector of drive
  1040.     adda.l    d0,a1        ; a1 = phys starting sector of 2nd FAT
  1041.  
  1042.     move.w    fsiz,d1        ; d1 = # FAT sectors to read
  1043.     subq.l    #1,d1        ;    = FAT size - 1
  1044.  
  1045. getb3:    move.w    sizr,d2        ; d2 = count per FAT sector
  1046.     subq.w    #1,d2
  1047.      clr.l    temp        ; initialize the sum
  1048. getb4:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1049.     move.l    a1,-(sp)    ; from sector a1
  1050.     move.w    cpun,-(sp)    ; physical unit
  1051.     addq.w    #2,(sp)        ; unit # including A: and B:
  1052.     move.w    #-1,-(sp)    ; using a long sector number
  1053.     move.w    #1,-(sp)    ; read 1 phys sector
  1054.     move.l    a0,-(sp)    ; buffer (in _dskbufp)
  1055.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  1056.     bsr    _ahdi_rw    ; ahdi_rw($a, buf, 1, -1, cpun, lsecno)
  1057.     adda    #16,sp        ; clean up stack
  1058.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1059.     tst.w    d0        ; read successful?
  1060.     beq    getb5        ; if so, go on normally
  1061.                 ; else let user retry
  1062. getba:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1063.     move.w    24(sp),d1    ; d1 = drive # excluding A: and B:
  1064.     bsr    critic        ; critical error handler
  1065.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1066.     cmpi.l    #CRITRETRY,d0    ; retry?
  1067.     beq.s    getb4        ; if so, try again
  1068.     bra    getb7        ; else return
  1069.  
  1070. getb5:    bsr    bsum        ; add up values in the sector
  1071.     addq    #1,a1        ; get ready for next sector
  1072.     dbra    d2,getb4    ; until one logical FAT sector is done
  1073.  
  1074.     bsr    csum        ; find the checksum
  1075.     move.b    d0,(a2)+    ; update checksum for this FAT sector
  1076.     dbra    d1,getb3    ; until all sectors are checked
  1077.  
  1078. getb6:    move.w    $4(sp),d0    ; d0 = dev number
  1079.     lea    mcflgs,a0    ; load address of mcflgs table
  1080.     clr.b    (a0,d0.w)    ; clear mcflg for dev
  1081.  
  1082.     lea    xst,a0        ; a0 -> drive existence table
  1083.     move.b    #2,(a0,d0.w)    ; dev definitely exists
  1084.  
  1085.     lea    fatst,a0    ; a0 -> FAT start sector table
  1086.     asl.w    #1,d0        ; offset = dev# * 2 (tbl of words)
  1087.     move    fatrec,(a0,d0.w); update FAT starting sect#
  1088.  
  1089.     lea    fatend,a0    ; a0 -> FAT end sector table
  1090.     move.w    fatrec,d1    ; d1 = fatend(dev)
  1091.     add.w    fsiz,d1        ;    = fatrec + fsiz - 1
  1092.     subq.w    #1,d1    
  1093.     move.w    d1,(a0,d0.w)    ; fatend(dev) = fatrec + fsiz - 1
  1094.  
  1095.     lea    start,a0    ; a0 -> beginning of start table
  1096.     asl.w    #1,d0        ; offset = dev# * 2 * 2 (tbl of longs)
  1097.     move.l    $6(sp),(a0,d0.w); update starting sect# of dev
  1098.  
  1099.     move.l    #bpbs,d0    ; no errors, return ptr to BPB
  1100.     bra.s    getb8        ; return
  1101.  
  1102. getb7:    moveq    #-1,d0        ; error
  1103. getb8:    rts
  1104.  
  1105.  
  1106. ;+
  1107. ; WORD getlhw(d0=offset)
  1108. ; returns word (low,high) from 0(D0,A0)
  1109. ;-
  1110.     .globl    getlhw
  1111. getlhw:    move    d1,-(sp)    ; preserve d1
  1112.     move.b    1(a0,d0.w),d1
  1113.     lsl.w    #8,d1
  1114.     move.b    0(a0,d0.w),d1
  1115.     move    d1,d0
  1116.     move    (sp)+,d1
  1117.     rts
  1118.  
  1119.  
  1120. ;+
  1121. ; bsum
  1122. ;
  1123. ; Passed:
  1124. ;    a0 = starting address of buffer to be summed
  1125. ;    temp.l = current sum
  1126. ;
  1127. ; Function:
  1128. ;      - sum up 512 bytes of a buffer 4 bytes at a time
  1129. ;    - save the sum in temp.l
  1130. ;
  1131. ; Algorithm for check summing the FAT:
  1132. ;    - add up bytes in the buffer 4 bytes at a time    (in bsum)
  1133. ;    - if the sum is non-zero, XOR the high word     (in csum)
  1134. ;      with the low word of the 4-byte result
  1135. ;    - now take this 2-byte result, and XOR its high    (in csum)
  1136. ;      byte with its low byte to get the final 1-byte
  1137. ;      result
  1138. ;-
  1139. bsum:    movem.l    d1/a0,-(sp)        ; save d1, a0
  1140.     move.l    temp,d0            ; d0 = current sum
  1141.     move    #127,d1            ; count
  1142. bsum0:    add.l    (a0)+,d0        ; add 4 bytes to sum
  1143.     dbra    d1,bsum0        ; until all bytes are added
  1144.     move.l    d0,temp            ; temp.l = new sum
  1145.     movem.l    (sp)+,d1/a0        ; restore d1, a0
  1146.     rts
  1147.  
  1148.  
  1149. ;+
  1150. ; csum
  1151. ; (a) XOR the high word with the low word of temp.l
  1152. ; (b) then XOR the high byte with the low byte of result of (a)
  1153. ;
  1154. ; Returns:
  1155. ;    d0.b = checksum
  1156. ;-
  1157. csum:    move.w    temp+2,d0        ; d0.w = low word of result
  1158.     eor.w    d0,temp            ; exclusive-or low and high word
  1159.     move.b    temp+1,d0        ; d0.b = low byte of xor-ed result
  1160.     eor.b    d0,temp            ; exclusive-or low and high byte
  1161.     move.b    temp,d0
  1162.     rts                ; d0.b = checksum
  1163.  
  1164.  
  1165. ;
  1166. ;+
  1167. ;  Read/Write sectors
  1168. ;
  1169. ;    Synopsis:    _ahdi_rw(rw, buf, count, recno, dev, lrecno)
  1170. ;        WORD rw        4(sp).w        ; non-zero -> write
  1171. ;        char *buf    6(sp).l
  1172. ;        WORD count    $a(sp).w
  1173. ;        WORD recno    $c(sp).w
  1174. ;        WORD dev    $e(sp).w
  1175. ;        LONG lrecno    $10(sp).l    ; optional
  1176. ;-
  1177.  
  1178. ; stack frame offsets
  1179. xrw    equ    8
  1180. xbuf    equ    10
  1181. xcount    equ    14
  1182. xrecno    equ    16
  1183. xdev    equ    18
  1184. xlrecno    equ    20
  1185.  
  1186.     .globl    _sasi_rw
  1187.     .globl    _ahdi_rw
  1188. _sasi_rw:
  1189. _ahdi_rw:
  1190.     link    a6,#0            ; create a frame pointer
  1191.     subq.w    #2,xdev(a6)        ; drive # excluding A: and B:
  1192.  
  1193.     move.w    xdev(a6),d0        ; d0 = device number
  1194.     btst.b    #3,xrw+1(a6)        ; is this a physical operation?
  1195.     beq.s    getcpun            ; if not, find physical unit number
  1196.     move.w    d0,cpun            ; else, dev# passed is phys unit #
  1197. ;+
  1198. ;  Aug-08-91    ml. The following line trashed the sizr set up
  1199. ;            by the logical mode rwabs() which calls the
  1200. ;            physical mode rwabs() recursively.
  1201. ;    move.w    #1,sizr            ; sector size ratio = 1
  1202. ;-
  1203.  
  1204.     bra    ahrw1            ; go start the r/w
  1205. getcpun:                ; map log -> phys unit number
  1206.     lea    pun,a0            ; a0 -> pun table
  1207.     move.b    (a0,d0.w),cpun+1    ; cpun = pun of dev
  1208.     
  1209.     lea    sratio,a0        ; a0 -> sector size ratio table
  1210.     move.b    (a0,d0.w),sizr+1    ; sizr = current sector size ratio
  1211.                     ;     (coerced to word)
  1212.     lea    start,a0        ; a0 -> start table
  1213.     move.w    d0,d1            ; d1 = drive #
  1214.     add.w    d1,d1            ; d1*2*2 (index into tbl of longs)
  1215.     add.w    d1,d1
  1216.     move.l    (a0,d1.w),cstart    ; cstart = dev starting sector
  1217.  
  1218.     btst.b    #1,xrw+1(a6)        ; ignore media change?
  1219.     bne    ahrw1            ; if yes, go ahead and do r/w
  1220.                     ; else check for media change
  1221.     lea    mcflgs,a0        ; a0 -> mcflgs of drive
  1222.     move.b    (a0,d0.w),d0        ; d0 = mcflg of dev
  1223.     beq    ahrw1            ; if media not changed, go do r/w
  1224.  
  1225.     cmpi.b    #2,d0            ; is media definitely changed?
  1226.     beq    retmc            ; if yes, return media has changed
  1227.                     ; else, check if media has changed
  1228.                     ; try to read dev's boot sector
  1229. chkmc:    move.l    cstart,-(sp)        ; dev starting sector
  1230.     move.w    cpun,-(sp)        ; physical unit number
  1231.     addq.w    #2,(sp)            ; unit # including A: and B:
  1232.     move.w    #-1,-(sp)        ; using a long sector number
  1233.     move.w    #1,-(sp)        ; 1 sector
  1234.     move.l    _dskbufp,-(sp)        ; buffer
  1235.     move.w    #$a,-(sp)        ; phys mode and no media change error
  1236.     bsr    _ahdi_rw        ; ahdi_rw($a, buf, 1, -1, cpun, sectno)
  1237.     adda    #16,sp            ; clean up stack
  1238.     tst.w    d0            ; read successful?
  1239.     beq.s    chkser            ; yes, go check serial number
  1240.  
  1241.     move.w    xdev(a6),d1        ; device number
  1242.     bsr    critic            ; call critical error handler
  1243.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1244.     beq.s    chkmc            ; if yes, go back and try it
  1245.     bra    ahrw7            ; else return
  1246.  
  1247. chkser:    lea    serno,a1        ; a1 -> serial #s table
  1248.     move.w    xdev(a6),d0        ; d0 = dev number
  1249.     mulu.w    #SERLEN,d0        ; *SERLEN for index into table
  1250.     adda.l    d0,a1            ; a1 -> serial # of dev
  1251.  
  1252.     move.l    _dskbufp,a2        ; a2 -> boot sector
  1253.     addq.w    #8,a2            ; a2 -> serial # in boot sector
  1254.      move.w    #SERLEN-1,d0        ; d0 = count for comparison
  1255. cmpser:    cmpm.b    (a2)+,(a1)+        ; serial # read ?= serial # recorded
  1256.     bne    ismc            ; if not, media has changed
  1257.     dbra    d0,cmpser        ; compare next byte of serial #
  1258.                     ; serial # hasn't changed, try FAT
  1259.     move.w    xdev(a6),d0        ; d0 = dev number
  1260.     lea    fatsum,a1        ; a1 -> fat checksum table
  1261.     move.w    #FATLEN,d1        ; d1.w = index into table
  1262.     mulu    d0,d1
  1263.     adda.l    d1,a1            ; a1 -> fat checksum of dev
  1264.  
  1265.     add.w    d0,d0            ; d0*2 = index into table of words
  1266.     lea    fatst,a2        ; a2 -> FAT start table
  1267.     move.w    (a2,d0.w),fatrec    ; fatrec = fatst(dev)
  1268.  
  1269.     lea    fatend,a2        ; a2 -> FAT end table
  1270.     move.w    (a2,d0.w),d1        ; d1 = counter to scan FAT table
  1271.     sub.w    fatrec,d1        ;    = fatend(dev) - fatst(dev)
  1272.  
  1273.     movea.l    cstart,a2        ; a2 = start sector of dev
  1274.     move.w    fatrec,d2        ; d2 = fatst(dev)
  1275.     mulu    sizr,d2            ; d2 = fatst(dev) in 512-byte sector
  1276.     adda.l    d2,a2            ; a2 = phys start sector of 2nd FAT
  1277.  
  1278.     movea.l    _dskbufp,a0        ; a0 -> dskbuf
  1279. cmpfat:    move.w    sizr,d2            ; d2 = # reads per FAT sector
  1280.     subq.w    #1,d2            ; d2 - 1 = counter
  1281.     clr.l    temp            ; initialize sum
  1282. cfat0:    movem.l    d1-d2/a0-a2,-(sp)    ; save d1, d2, a0, a1, a2
  1283.                     ; try to read this FAT sector
  1284.     move.l    a2,-(sp)        ; at sector a2
  1285.     move.w    cpun,-(sp)        ; physical unit number
  1286.     addq.w    #2,(sp)            ; unit # including A: and B:
  1287.     move.w    #-1,-(sp)        ; using a long sector number
  1288.     move.w    #1,-(sp)        ; 1 sector
  1289.     move.l    a0,-(sp)        ; buffer
  1290.     move.w    #$a,-(sp)        ; phys mode and no media change error
  1291.     bsr    _ahdi_rw        ; ahdi_rw($a, buf, 1, -1, cpun, sectno)
  1292.     adda    #16,sp            ; clean up stack
  1293.     movem.l    (sp)+,d1-d2/a0-a2    ; restore d1, d2, a0, a1, a2
  1294.     tst.w    d0            ; read successful?
  1295.     beq.s    chkfat            ; if yes, go check sum FAT sectors
  1296.                     ; else assume it's read error
  1297.     movem.l    d1-d2/a0-a2,-(sp)    ; save registers d1, d2, a0, a2
  1298.     move.w    xdev(a6),d1        ; drive number
  1299.     bsr    critic
  1300.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers d1, d2, a0, a2
  1301.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1302.     beq.s    cfat0            ; if yes, go back and try it
  1303.     bra    ahrw7            ; else return
  1304.  
  1305. chkfat:    bsr    bsum            ; if ok, sum the sector
  1306.     addq    #1,a2            ; ready for try next sector
  1307.     dbra    d2,cfat0        ; until one FAT sector is summed
  1308.  
  1309.     bsr    csum            ; find the checksum
  1310.     cmp.b    (a1)+,d0        ; checksum recorded ?= checksum found
  1311.     bne    ismc            ; if not, media has changed
  1312.     dbra    d1,cmpfat        ; until all sectors are checked
  1313.  
  1314.     lea    mcflgs,a0        ; a0 -> mcflgs table
  1315.     adda.w    xdev(a6),a0        ; a0 -> mcflg of drive
  1316.     clr.b    (a0)            ; clear mcflg for dev
  1317.  
  1318. ahrw1:    tst.w    xcount(a6)        ; any sector to r/w?
  1319.     beq    ahrw6            ; if =0, done
  1320.  
  1321.     cmpi.w    #-1,xrecno(a6)        ; does recno = -1?
  1322.     bne.s    ahrw2            ; if not, we have a word record #
  1323.     movea.l    xlrecno(a6),a1        ; a1.l = start record #
  1324.     bra.s    ahrw3
  1325. ahrw2:    moveq    #0,d0            ; coerce to long
  1326.     move.w    xrecno(a6),d0        ; d0.l = recno
  1327.     movea.l    d0,a1            ; a1.l = start record #
  1328.  
  1329. ahrw3:    move.l    a1,strec        ; save first sector to r/w
  1330.     move.l    a1,d1            ; d1.l = starting sector to r/w
  1331.     moveq    #0,d2            ; coerce to long
  1332.     move.w    xcount(a6),d2        ; d2.l = #sectors to r/w
  1333.     adda.l    d2,a1            ; a1.l = last sector to r/w
  1334.     subq.l    #1,a1            ;      = first sector + count - 1
  1335.     move.l    a1,endrec        ; save last sector to r/w
  1336.     move.l    xbuf(a6),stbuf        ; save starting buffer address
  1337.  
  1338.     btst.b    #3,xrw+1(a6)        ; physical operation?
  1339.     bne.s    ahrw4            ; if so, ready to r/w
  1340.                     ; else log -> phys sector mapping
  1341.     mulu    sizr,d1            ; d1.l    = phys start sector to r/w
  1342.     add.l    cstart,d1        ;    = dev start sect + sect #
  1343.     mulu    sizr,d2            ; d2.l = # phys 512-byte sects to r/w
  1344.  
  1345. ahrw4:    move.w    xdev(a6),-(sp)        ; device # (excluding A: and B:)
  1346.     move.l    d1,-(sp)        ; starting sector
  1347.     move.l    d2,-(sp)        ; count (in sectors)
  1348.     move.l    xbuf(a6),-(sp)        ; buffer
  1349.     move.w    xrw(a6),-(sp)        ; read write flag
  1350.     bsr    _do_rw            ; do the read or write
  1351.     adda    #16,sp            ; clean up stack
  1352.     tst.l    d0            ; successful?
  1353.     beq.s    chkwr            ; if so, go on to wrap up
  1354.  
  1355.     cmpi.l    #E_CHNG,d0        ; media change detected?
  1356.     bne    ahrw7            ; if not, give up
  1357.     btst.b    #3,xrw+1(a6)        ; is this a physical operation?
  1358.     bne    ahrw7            ; if so, return media change error
  1359.     bra    chkmc            ; and go check if media has changed 
  1360.                     ; check if wrote to boot sector
  1361. chkwr:    move.w    xrw(a6),d0        ; d0 = r/w and flags word
  1362.     btst    #0,d0            ; read or write?
  1363.     beq    ahrw6            ; if read, done
  1364.     btst.b    #6,cpun+1        ; is drive removable?
  1365.     beq    ahrw6            ; if not, done
  1366.     btst    #3,d0            ; was it a physical operation?
  1367.     bne    ahrw6            ; if it was, done
  1368.     tst.l    strec            ; wrote to boot sector?
  1369.     bne.s    wrfat            ; if not, check if wrote to FATs
  1370.     lea    mcflgs,a0        ; else, a0 -> mcflgs table
  1371.     adda.w    xdev(a6),a0        ; a0 -> dev's mcflg
  1372.     move.b    #2,(a0)            ; assume medium has changed
  1373.                     ; check if wrote to FATs
  1374. wrfat:    lea    fatend,a0        ; a0 -> fatend table
  1375.     move.w    xdev(a6),d0        ; d0 = device number
  1376.     add.w    d0,d0            ; d0*2 = index into table of words
  1377.     moveq    #0,d1            ; coerce to long
  1378.     move.w    (a0,d0.w),d1        ; d1 = last sector of last FAT
  1379.     cmp.l    strec,d1        ; wrote beyond the last FAT?
  1380.     blt    ahrw6            ; if so, done
  1381.  
  1382.     lea    fatst,a0        ; a0 -> fatst table
  1383.     moveq    #0,d2            ; coerce to long
  1384.     move.w    (a0,d0.w),d2        ; d2 = first sector of last FAT
  1385.     cmp.l    endrec,d2        ; wrote before the last FAT?
  1386.     bgt    ahrw6            ; if so, done
  1387.                     ; else update FAT sector checksums
  1388.     move.l    stbuf,a0        ; a0 -> buffer w/ written data
  1389.     lea    fatsum,a1        ; a1 -> start of fatsum table
  1390.     move.w    xdev(a6),d0        ; d0 = dev number
  1391.     mulu.w    #FATLEN,d0        ; d0 = offset to dev's FAT chksum
  1392.     adda.l    d0,a1            ; a1 -> dev's first FAT chksum
  1393.     move.l    strec,d0        ; d0 = first sector wrote to
  1394.     sub.l    d2,d0            ; d0 = strec - start(last FAT)
  1395.     beq.s    wrfat2            ; if strec = start(last FAT), 
  1396.                     ;     no adjustments needed
  1397.      blt.s    wrfat1            ; if strec < start(last FAT)
  1398.                     ;     begin from start(last FAT)
  1399.     move.l    strec,d2        ; else begin from strec
  1400.     adda.l    d0,a1            ; a1 -> fatsum to be updated
  1401.     bra.s    wrfat2
  1402.  
  1403. wrfat1:    neg.l    d0            ; d0 = index into stbuf
  1404.     asl.l    #8,d0            ;    = (start(last FAT) - strec)*512
  1405.     add.l    d0,d0
  1406.     adda.l    d0,a0            ; a0 -> addr of buf for update
  1407.  
  1408. wrfat2:    cmp.l    endrec,d1        ; if end(last FAT) <= endrec
  1409.     ble.s    wrfat3            ;     stop at end(last FAT)
  1410.     move.l    endrec,d1        ; else stop at endrec
  1411.  
  1412. wrfat3:    sub    d2,d1            ; d1 = # sectors to be processed
  1413. wrfat4:    move.w    sizr,d2            ; d2 = # phys sect per log sect
  1414.     subq.w    #1,d2            ; dbra likes one less
  1415.     clr.l    temp            ; initialize sum
  1416. wrfat5:    bsr    bsum            ; sum up one 512-byte sector
  1417.     adda.l    #512,a0            ; point to next 512 bytes
  1418.     dbra    d2,wrfat5        ; until one logical sector is done
  1419.     bsr    csum            ; obtain checksum
  1420.     move.b    d0,(a1)+        ; record new fat checksum
  1421.     dbra    d1,wrfat4        ; do until all are updated
  1422.  
  1423. ahrw6:    clr.l    d0            ; got here with no errors!
  1424.     bra.s    ahrw7
  1425.  
  1426. ismc:    lea    mcflgs,a0        ; a0 -> mcflgs table
  1427.     adda.w    xdev(a6),a0        ; a0 -> dev's mcflg
  1428.     move.b    #2,(a0)            ; set mcflg for dev to has changed
  1429.     lea    xst,a0            ; a0 -> drive existence table
  1430.     adda.w    xdev(a6),a0        ; a0 -> xst flag of dev
  1431.     move.b    #2,(a0)            ; assume dev exists
  1432. retmc:    move.l    #E_CHNG,d0        ; yes, return media change error
  1433.  
  1434. ahrw7:    btst.b    #0,xrw+1(a6)        ; read or write?
  1435.     bne.s    ahrwd            ; if write, done
  1436.     tst.b    _cachexst        ; does a cache exist?
  1437.     beq.s    ahrwd            ; if not, done
  1438.                     ; else dump the cache
  1439.     move.l    d0,-(sp)        ; save the status
  1440.     move    sr,-(sp)        ; go to IPL 7
  1441.     ori    #$700,sr        ; no interrupts right now kudasai
  1442.     movecacrd0            ; d0 = (cache control register)
  1443.     ori.w    #$808,d0        ; dump both the D and I cache
  1444.     moved0cacr            ; update cache control register
  1445.     move    (sp)+,sr        ; restore interrupt state
  1446.     move.l    (sp)+,d0        ; restore the return value
  1447.  
  1448. ahrwd:    unlk    a6
  1449.     rts
  1450.  
  1451.  
  1452. ;+
  1453. ; smove() - Copy unaligned sectors (this is *supposed* to be slow!)
  1454. ;
  1455. ; Passed:
  1456. ;    d0 = # of sectors to be moved
  1457. ;    d1 = size of operation    (0 - byte; 2 - long;)
  1458. ;    a2 -> source buffer
  1459. ;    a1 -> dest buffer
  1460. ;
  1461. ; Trashes: d0, a1, a2
  1462. ;-
  1463. smove:    move.w    d1,-(sp)        ; save size of operation
  1464.     neg.w    d1            ; d0 = count
  1465.     addi.w    #9,d1            ;    = (# sectors * 512) >> op size
  1466.     asl.w    d1,d0            ;
  1467.     subq.w    #1,d0            ; dbra likes one less
  1468.     move.w    (sp)+,d1        ; restore operation size
  1469.     bne.s    smove2            ; if non-zero, use move longs
  1470.  
  1471. smove1:    move.b    (a2)+,(a1)+
  1472.     dbra    d0,smove1
  1473.     rts
  1474.  
  1475. smove2:    move.l    (a2)+,(a1)+
  1476.     dbra    d0,smove2
  1477.     rts
  1478.  
  1479.  
  1480. ;
  1481. ;+
  1482. ; _do_rw - called to read/write no more than 128K to an even boundary
  1483. ;
  1484. ; Passed:
  1485. ;    rw    4(sp).w        ; non-zero -> write
  1486. ;    buf    6(sp).l
  1487. ;    count    $a(sp).l    ; in # phys (512-byte) sectors
  1488. ;    recno    $e(sp).l    ; physical starting sector for r/w
  1489. ;    dev    $12(sp).w    ; log dev # exluding A: and B:
  1490. ;
  1491. ; Assumes:
  1492. ;    cpun = current physical unit to r/w
  1493. ;    if in logical mode, cstart = physical starting sector # of curr dev
  1494. ;
  1495. ; Mar-05-1990 ml.
  1496. ;    All I/O to ACSI and SCSI non-accessible memory will be done by
  1497. ; using the fast ram buffer (if there is one) or the diskbuf as an inter-
  1498. ; mediate stop for the transfer.
  1499. ;
  1500. ; ACSI accessible memory:    $00000000 -> $003fffff
  1501. ;                $ff000000 -> $ff3fffff
  1502. ; SCSI non-accessible 
  1503. ; memory on the TT:        $c0000000 -> $fcffffff
  1504. ;                $fe000000 -> $feffffff
  1505. ;
  1506. ; Mar-07-1990 ml.
  1507. ;    Do not have to take care of cases when Rwabs() is supplied with
  1508. ; a buffer that would cross different kinds of memory.
  1509. ; ("It's deadly!" said AKP. :) )
  1510. ;-
  1511. yrw    equ    $8
  1512. ybuf    equ    $a
  1513. ycount    equ    $e
  1514. yrecno    equ    $12
  1515. ydev    equ    $16
  1516.  
  1517. ; Memory that ACSI _can_ DMA to
  1518. STDUAL    equ    $003fffff    ; upper limit of ST dual-purpose RAM
  1519. STCMPIL    equ    $ff000000    ; lower limit of ST compatible image
  1520. STCMPIH    equ    $ff3fffff    ; upper limit of ST compatible image
  1521.  
  1522. ; Memory that SCSI _cannot_ DMA to (non-DW)
  1523. A32D16L    equ    $c0000000    ; lower limit of A32:D16 Memory/Peripherals
  1524. A32D16H    equ    $fcffffff    ; upper limit of A32:D16 Memory/Peripherals 
  1525. VA24D16    equ    $fe000000    ; lower limit of VMEbus A24:D16
  1526. VA16D16    equ    $feffffff    ; upper limit of VMEbus    A16:D16
  1527.  
  1528. ; Cookies
  1529. _FRB    equ    $5f465242        ; _FRB
  1530.  
  1531. _do_rw:    link    a6,#0            ; create a frame pointer
  1532.     move.l    ycount(a6),d2        ; d2.l = # sectors requested to r/w
  1533.      movea.l    ybuf(a6),a1        ; a1.l = buffer addr to r/w
  1534.     btst.b    #3,cpun+1        ; talking SCSI?
  1535.     bne    scrw0            ; if yes, go for it
  1536.                     ; else talk ACSI
  1537.     cmp.l    #MAXACSECTS,d2        ; more than one ACSI DMAful?
  1538.     bls.s    acrw1            ; if not, ready to r/w
  1539.     move.l    #MAXACSECTS,d2        ; else r/w only one ACSI DMAful
  1540.  
  1541. acrw1:    btst.b    #0,ybuf+3(a6)        ; buffer on odd boundary?
  1542.     bne.s    itrw0            ; if so, do intermediate transfer
  1543.  
  1544.     cmpa.l    #STDUAL,a1        ; buf within ACSI accessible memory?
  1545.     bls    rw1            ; if so, go ahead with the I/O
  1546.     cmpa.l    #STCMPIL,a1        ; else, do intermediate transfer
  1547.     bcs.s    itrw0
  1548.     cmpa.l    #STCMPIH,a1
  1549.     bls    rw1
  1550.                     ; doing intermediate transfer
  1551. itrw0:    moveq    #0,d1            ; assume moving 1 byte at a time
  1552.     btst.b    #0,ybuf+3(a6)        ; odd boundary?
  1553.     bne.s    itrw1            ; if so, assumption ok
  1554.     moveq    #2,d1            ; else move 1 long at a time
  1555.  
  1556. itrw1:    tst.l    frbbuf            ; is there a fast RAM buffer?
  1557.     bne.s    itrw2            ; if there is one, use it
  1558.                     ; else look for _FRB
  1559.     move.l    d1,-(sp)        ; save d1
  1560.     move.l    #frbbuf,-(sp)        ; pointer to fast RAM buffer
  1561.     move.l    #_FRB,-(sp)        ; looking for cookie _FRB
  1562.     bsr    _getcookie        ; 
  1563.     addq.w    #8,sp            ; clean up stack
  1564.     move.l    (sp)+,d1        ; restore d1
  1565.     tst.w    d0            ; found _FRB?
  1566.     bne.s    itrw2            ; if so, use it
  1567.                     ; else use dskbuf
  1568.     movea.l    _dskbufp,a1        ; a1 -> dskbuf
  1569.     cmpi.w    #2,d2            ; can only do 2 at a time tops
  1570.     bls.s    itrw3
  1571.     move.w    #2,d2
  1572.     bra.s    itrw3
  1573.  
  1574. itrw2:    movea.l    frbbuf,a1        ; use the Fast RAM Buffer
  1575.     cmpi.w    #RAMRSV,d2        ; can only do RAMRSV at a time tops
  1576.     bls.s    itrw3
  1577.     move.w    #RAMRSV,d2
  1578.  
  1579. itrw3:    btst.b    #0,yrw+1(a6)        ; is this a read?
  1580.     beq.s    rw1            ; if so, go fill buffer from disk
  1581.                     ; else fill buffer here
  1582.     move.l    a1,-(sp)        ; preserve a1 = dest
  1583.     movea.l    ybuf(a6),a2        ; a2 = source
  1584.     move.w    d2,d0            ; # sectors to be moved
  1585.     bsr    smove            ; move sectors from a2 to a1
  1586.     movea.l    (sp)+,a1        ; restore a1.l = dest
  1587.     bra.s    rw1            ; go do the r/w
  1588.  
  1589. scrw0:    cmpi.l    #MAXSCSECTS,d2        ; more than one SCSI DMAful?
  1590.     bls.s    scrw1            ; if not, ready to r/w
  1591.     move.l    #MAXSCSECTS,d2        ; r/w only one SCSI DMAful?
  1592.  
  1593. scrw1:    
  1594.  
  1595. .if    SCDMA                ; if doing SCSI DMA
  1596. .if    !SCFRDMA            ; if no SCSI DMA to fast RAM
  1597.     cmpi.b    #$01,ybuf(a6)        ; is destination buffer in fast RAM?
  1598.     beq    itrw0            ; if so, do intermediate transfer
  1599. .endif    ;!SCFRDMA
  1600.  
  1601.     cmpa.l    #A32D16L,a1        ; buf in SCSI non-accessible
  1602.     bcs.s    rw1            ;  memory?
  1603.     cmpa.l    #A32D16H,a1        ; if so, do intermediate transfer
  1604.     bls    itrw0            ; else, go ahead with the I/O
  1605.     cmpa.l    #VA24D16,a1
  1606.     bcs.s    rw1
  1607.     cmpa.l    #VA16D16,a1
  1608.     bls    itrw0
  1609. .endif    ;SCDMA
  1610.  
  1611.     bra.s    rw1
  1612.  
  1613. rw0:    movea.l    ybuf(a6),a1        ; a1 = buffer address for r/w
  1614. rw1:    move.w    _retries,retrycnt    ; setup retry counter
  1615.  
  1616.     btst.b    #2,yrw+1(a6)        ; are retries disabled?
  1617.     beq.s    rw2            ; no, act normally
  1618.     move.w    #0,retrycnt        ; yes, so set retrycnt to zero
  1619.  
  1620. rw2:    movem.l    d1-d2/a1,-(sp)        ; preserve d1, d2 and a1
  1621.     move.w    cpun,-(sp)        ; dev.w
  1622.     move.l    a1,-(sp)        ; buf.l
  1623.     move.w    d2,-(sp)        ; count.w
  1624.     move.l    yrecno(a6),-(sp)    ; sect.L
  1625.     cmpi.l    #MAXACSECTS,d2        ; more than hr/w can handle?
  1626.     bhi.s    rw4            ; if so, use extended call (SCSI only)
  1627.     btst.b    #0,yrw+1(a6)        ; read or write?
  1628.     bne.s    rw3            ; (write)
  1629.     bsr    _hread            ; read sectors
  1630.     bra.s    rw6
  1631. rw3:    bsr    _hwrite            ; write sectors
  1632.     bra.s    rw6
  1633. rw4:    btst.b    #0,yrw+1(a6)        ; extended read or write?
  1634.     bne.s    rw5            ; (write)
  1635.     bsr    _xtdread        ; read sectors
  1636.     bra.s    rw6
  1637. rw5:    bsr    _xtdwrt            ; write sectors
  1638. rw6:    adda    #12,sp            ; (cleanup stack)
  1639.     movem.l    (sp)+,d1-d2/a1        ; restore d1, d2 and a1
  1640.     tst.l    d0            ; errors?
  1641.     beq    rwf            ; no error --> successful
  1642.     bmi.s    rw9            ; timed out --> retry
  1643.  
  1644.     movem.l    d1-d2/a1,-(sp)        ; preserve d1, d2 and a1
  1645.     bsr    errcode            ; find error code
  1646.     movem.l    (sp)+,d1-d2/a1        ; restore d1, d2 and a1
  1647.  
  1648.     cmpi.b    #MDMCHGD,d0        ; media change detected?
  1649.     bne.s    rw7            ; if not, fine
  1650.                     ; else record media may be changed
  1651.     move.b    #1,d0            ; d0.b = 1 (may be changed)
  1652.     bsr    s_mc_xst        ; set mcflgs and xst flags for all dev
  1653.  
  1654.     btst.b    #1,yrw+1(a6)        ; ignore media change?
  1655.     bne    rw2            ; if so, retry operation
  1656.     move.l    #E_CHNG,d0        ; else return media change
  1657.     bra    rwr
  1658.     
  1659. rw7:    cmpi.b    #WRTPRTD,d0        ; write on write-protected media?
  1660.     bne.s    rw8            ; if not, fine
  1661.     move.l    #EWRPRO,d0        ; else return write-protection error
  1662.     bra.s    rwa
  1663.  
  1664. rw8:    cmpi.b    #DRVNRDY,d0        ; drive not ready?
  1665.     bne.s    rw9            ; if not, fine
  1666.     move.l    #EDRVNR,d0        ; else return drive not ready
  1667.     bra.s    rwa
  1668.  
  1669. rw9:    subq.w    #1,retrycnt        ; drop retry count and retry
  1670.     bpl    rw2
  1671.  
  1672.     move.l    #EREADF,d0        ; read error code
  1673.     btst.b    #0,yrw+1(a6)        ; is it a write?
  1674.     beq.s    rwa            ; (read)
  1675.     move.l    #EWRITF,d0        ; write error code
  1676.  
  1677. rwa:    btst.b    #3,yrw+1(a6)        ; is this a physical operation?
  1678.     bne    rwr            ; if so, exit
  1679.                     ; else call critical error handler
  1680.     movem.l    d1-d2/a1,-(sp)        ; preserve d1, d2 and a1
  1681.     move.w    ydev(a6),d1        ; d1 = drive number
  1682. rwe:    bsr    critic
  1683.     movem.l    (sp)+,d1-d2/a1        ; restore d1, d2 and a1
  1684.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1685.     beq    rw2            ; if yes, go retry
  1686.     bra.s    rwr            ; else, head home
  1687.  
  1688. rwf:    lea    rw0,a0            ; exec of next r/w starts at rw1
  1689.     cmpa.l    ybuf(a6),a1        ; was alternate buffer used?
  1690.     beq.s    rw10            ; if not, go on to next r/w
  1691.                     ; else take care of transfer
  1692.     lea    itrw3,a0        ; exec of next r/w starts at itrw3
  1693.     btst.b    #0,yrw+1(a6)        ; was it a write?
  1694.     bne.s    rw10            ; if it was, go on to next write
  1695.                     ; else move data to supplied buffer
  1696.     move.l    a1,-(sp)        ; save address of alternate buffer
  1697.     movea.l    a1,a2            ; a2 = address of alternate buffer
  1698.     movea.l    ybuf(a6),a1        ; a1 = address of supplied buffer
  1699.     move.w    d2,d0            ; d0 = # of sectors to move
  1700.     bsr    smove            ; move data from alt buf to sup buf
  1701.     move.l    (sp)+,a1        ; restore address of alternate buffer
  1702.  
  1703. rw10:    sub.l    d2,ycount(a6)        ; ycount(a6) = # sects left to be done
  1704.     beq.s    rwd            ; if no more left, done
  1705.                     ; else get ready for next r/w
  1706.     add.l    d2,yrecno(a6)        ; yrecno(a6) = next starting sector
  1707.     move.l    d2,d0            ; d0 = # bytes done
  1708.     asl.l    #8,d0            ;    = # sectors done * 512
  1709.     add.l    d0,d0            ; 
  1710.     add.l    d0,ybuf(a6)        ; buf += (sectors_done * sector size)
  1711.     cmp.l    ycount(a6),d2        ; amount to r/w > amount doable?
  1712.     bls.s    rw11            ; if so, r/w amount doable
  1713.     move.l    ycount(a6),d2        ; else r/w all of it
  1714. rw11:    jmp    (a0)            ; go on to next r/w
  1715.  
  1716. rwd:    moveq    #0,d0            ; got here with no errors!
  1717. rwr:    unlk    a6            ; head home
  1718.     rts
  1719.  
  1720.  
  1721. ;
  1722. ;+
  1723. ; Check for media change on hard disk
  1724. ; Synopsis:    _sasi_mediach(dev)
  1725. ;        WORD dev;        4(sp).w
  1726. ;
  1727. ; Returns:    0L - media definitely has not changed
  1728. ;        1L - media _may_ have changed
  1729. ;        2L - media definitely has changed
  1730. ;
  1731. ; Uses:        d0, d1, a0, a1
  1732. ;
  1733. ; Comments:
  1734. ; Apr-4-1989    ml.    Add in grace period between _sasi_mediach()s.
  1735. ;            If _sasi_mediach() was called less than 1 s
  1736. ;            (200 _hz_200 clock ticks) ago, and medium was 
  1737. ;            not changed then, assume medium still has not 
  1738. ;            changed.
  1739. ;-
  1740. _sasi_mediach:
  1741.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  1742.     move.w    4(sp),d1        ; d1 = current drive
  1743.     lea    mcflgs,a0        ; a0 = pointer to mcflgs
  1744.     moveq    #0,d0            ; d0 = mcflg for current drive
  1745.     move.b    (a0,d1.w),d0    
  1746.     tst.b    d0            ; has medium changed?
  1747.     bne.s    decided            ; if yes or maybe, return result
  1748.                     ; else verify that it has not
  1749.     move.l    lastmdctm,d2        ; time media change was last called
  1750.     cmp.l    _hz_200,d2        ; while (_hz_200 <= lastmdctm)
  1751.     bcc.s    decided            ;    assume medium not changed
  1752.  
  1753.     lea    pun,a1            ; ptr to beginning of pun table
  1754.     move.b    (a1,d1.w),cpun+1    ; cpun = pun current drive belongs to
  1755.  
  1756.     btst.b    #6,cpun+1        ; is pun removable?
  1757.     beq.s    notchngd        ; if not, medium has not changed
  1758.  
  1759.     move.w    cpun,-(sp)        ; physical unit number
  1760.     bsr    _untrdy            ; verify by doing test unit ready
  1761.     addq.l    #2,sp
  1762.     move.l    _hz_200,lastmdctm    ; update time for last _sasi_mediach()
  1763.     addi.l    #200,lastmdctm        ; 
  1764.     tst.w    d0            ; return good status?
  1765.     beq.s    notchngd        ; if yes, return medium not changed
  1766.     moveq    #1,d0            ; else return medium may have changed
  1767.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  1768.     bra.s    decided
  1769. notchngd:
  1770.     moveq    #0,d0            ; return medium has not changed
  1771. decided:
  1772.     rts
  1773.  
  1774.  
  1775. ;+
  1776. ; s_mc_xst - set mcflgs and drive existence flags 
  1777. ;         for drives belonging to the current
  1778. ;         physical unit to value passed
  1779. ;
  1780. ; Passed:    d0.b - value to set to
  1781. ;-
  1782. s_mc_xst:
  1783.     movem.l    d1-d2/a0-a2,-(sp) ; save registers
  1784.     lea    pun,a0        ; a0 -> pun table
  1785.     lea    mcflgs,a1    ; a1 -> mcflgs table
  1786.     lea    xst,a2        ; a2 -> drive existence table
  1787.     move.w    cpun,d1        ; d1 = current physical unit #
  1788.     moveq    #0,d2        ; d2 = logical drive #; index into tables
  1789. set0:    btst.b    #7,(a0,d2.w)    ; a valid logical drive?
  1790.     bne.s    setr        ; if not, done
  1791.     cmp.b    (a0,d2.w),d1    ; else, does it belong to this physical unit?
  1792.     bne.s    set1        ; if not, move on to next logical drive
  1793.     move.b    d0,(a1,d2.w)    ; else change its mcflg to value passed
  1794.     move.b    d0,(a2,d2.w)    ; and change its xst to value passed
  1795. set1:    addq.w    #1,d2        ; try next one in forward direction
  1796.     cmp.w    #MAXUNITS,d2    ; all units checked?
  1797.     blt.s    set0        ; if not, go on
  1798. setr:    movem.l    (sp)+,d1-d2/a0-a2 ; else restore registers
  1799.     rts            ; and return
  1800.  
  1801.  
  1802. ;
  1803. ;+
  1804. ; Resident Installer
  1805. ;-
  1806.     .globl    i_sasi6
  1807. i_sasi6:
  1808. ;+
  1809. ; 02-Apr-1991    ml.    The following is illegal, because i_sasi1 is 
  1810. ;            external.
  1811. ;    move.l    #(i_sasi1-i_sasi),tokeep ; at least keep this much
  1812. ;-
  1813.     move.l    #i_sasi1,tokeep ; tokeep = amount of code to be kept
  1814.     subi.l    #i_sasi,tokeep
  1815.     cmpi.w    #512,maxssz    ; maxssz > 512 bytes?
  1816.     bls.s    nboot1        ; if not, don't need to replace GEMDOS buffers
  1817.                 ; else check if there is enough memory for
  1818. chkmem:    bsr    chklstmem    ;   new GEMDOS buffer lists
  1819.     tst.l    d0        ; enough?
  1820.     bpl.s    okbig        ; if so, build the list
  1821.     move.w    defbigsect,d0    ; d0 = minimum big sector
  1822.     cmp.w    maxssz,d0    ; is maxssz >= minimum big sector?
  1823.     bcc.s    regsect        ; if so, give up
  1824.     move.w    d0,maxssz    ; else try minimum big sector
  1825.     bra.s    chkmem
  1826. regsect:
  1827.     move.w    #512,maxssz    ; will not handle big sectors
  1828.     bra.s    nboot1
  1829.  
  1830. okbig:    move.l    d1,tokeep    ; update amount of memory to be kept
  1831.     lea    i_sasi1,a0    ; a0 -> beginning of new buffer lists
  1832.     moveq    #3,d1        ; d1 = count = 4 buffers - 1
  1833.     bsr    list_init    ; initialize the buffer list
  1834.     clr.l    (a0,d0.w)    ; cut 1 list of 4 buffers to 2 lists of 2
  1835.     move.l    a0,_bufl    ; _bufl[0] -> 1st new buffer list
  1836.     add.l    d0,d0        ; d0 = offset to beginning of 2nd buffer list
  1837.     adda.l    d0,a0        ; a0 = head of 2nd buffer list
  1838.     move.l  a0,_bufl+4    ; _bufl[1] -> 2nd new buffer list
  1839.  
  1840. nboot1:    bsr    pool_install    ; attempt to install more OS pool
  1841.     add.l    d0,tokeep    ; update amount of memory to be kept
  1842.  
  1843. ;    clr.l    frbbuf        ; assume no _FRB
  1844. ;    move.l    #frbbuf,-(sp)    ; pointer to fast RAM buffer
  1845. ;    move.l    #$5f465242,-(sp)    ; cookie "_FRB"
  1846. ;    bsr    _getcookie    ; try to find _FRB in cookie jar
  1847. ;    addq.w    #8,sp        ; clean up stack
  1848.  
  1849.     move.l    _hz_200,lastmdctm    ; initialize media change time
  1850.     tst.w    bootloaded    ; if bootloaded, then already in super mode
  1851.     bne.s    nboot2        ; (already there)
  1852.     move.l    savssp,-(sp)    ; become a mild mannered user process
  1853.     move.w    #$20,-(sp)    ; Super(savssp)
  1854.     trap    #1
  1855.     addq.w    #6,sp
  1856.  
  1857. ;+
  1858. ; Terminate and stay resident;
  1859. ; installed driver under GEMDOS.
  1860. ;-
  1861.     move.l    tokeep,d0    ; compute value for Ptermres()
  1862.     add.l    #$0100,d0    ; for basepage
  1863.     move.l    d0,-(sp)    ; save D0
  1864.     pea    msg_nbl(pc)    ; print announcement
  1865.     move.w    #9,-(sp)
  1866.     trap    #1
  1867.     addq.l    #6,sp
  1868.     move.l    (sp)+,d0
  1869.     move.w    #0,-(sp)    ; exit code
  1870.     move.l    d0,-(sp)
  1871.     move.w    #$31,-(sp)    ; terminate and stay resident
  1872.     trap    #1        ; should never come back...
  1873.     illegal
  1874.  
  1875.  
  1876. ;+
  1877. ;  Return to TOS ROMs
  1878. ;    - set default boot device to C:
  1879. ;    - Print silly message
  1880. ;    - Mshrink() memory that was alloc'd to us
  1881. ;    - set magic# in D7 for TOS ROMs
  1882. ;    - RTS back to ROMs
  1883. ;-
  1884. nboot2:    move.l    tokeep,d0    ; compute value for Mshrink
  1885.     add.l    #$1c,d0        ; for file header
  1886.     move.l    d0,-(sp)    ; save D0
  1887.     pea    msg_bl(pc)    ; print announcement
  1888.     move.w    #9,-(sp)
  1889.     trap    #1
  1890.     addq.l    #6,sp        ; clean up stack
  1891.  
  1892.     move.w    d4,d1        ; physical unit # in d4.w?
  1893.     bpl.s    bd0        ; if so, good
  1894.                 ; else it's in hi 3 bits of d7.b
  1895.     move.b    d7,d1        ; d1.b = physical unit # boot loaded from
  1896.     lsr.b    #5,d1        ;      = xxx00000 >> 5
  1897. bd0:    lea    pun,a0        ; a0 -> pun table
  1898.     moveq    #0,d2        ; d2 = boot dev
  1899. bd1:    move.b    (a0,d2.w),d0    ; d0.b = unit #
  1900.     andi.b    #$0f,d0        ; mask out flags
  1901.     cmp.b    d0,d1        ; d2 belongs to physical unit booted from?
  1902.     beq.s    bd2        ; if yes, set (d2) as boot device
  1903.     addq.w    #1,d2        ; else try next logical unit
  1904.     bra.s    bd1
  1905. bd2:    addq.w    #2,d2        ; offset for drive A and B
  1906.     move.w    d2,_bootdev    ; set default boot device to (d2)
  1907.  
  1908.     move.l    baseaddr,-(sp)
  1909.     clr.w    -(sp)
  1910.     move.w    #$4a,-(sp)    ; Mshrink(...)
  1911.     trap    #1
  1912.     adda    #12,sp        ; (cleanup stack)
  1913.  
  1914.     move.w    _bootdev,-(sp)    ; set boot dev as default drive
  1915.     move.w    #$e,-(sp)    ; Dsetdrv(_bootdev)
  1916.     trap    #1
  1917.     addq.w    #4,sp        ; cleanup stack
  1918.  
  1919.     move.l    #rootpath,-(sp)    ; set root as current directory
  1920.     move.w    #$3b,-(sp)    ; Dsetpath('\')
  1921.     trap    #1
  1922.     addq.w    #6,sp        ; cleanup stack
  1923. ;
  1924. ;    move.l    _sysbase,a0    ; get the system header address
  1925. ;    move.l    $18(a0),d0    ; d0.l = MMDDYYYY of ROM date
  1926. ;    swap    d0        ; d0.l = YYYYMMDD of ROM date
  1927. ;    cmp.l    #CHKDATE,d0    ; does this version of ROM need bootstop?
  1928. ;    bcs.s    stopall        ; yup, if OS is built before 4/22/87
  1929. ;    move.b    puns+1,d7    ; else prevent processed units from booting
  1930. ;    subq.b    #1,d7        ; unit # = # of units - 1
  1931. ;    lsl.b    #5,d7
  1932. ;    rts            ; return to TOS ROMs
  1933. ;
  1934. ; Stop ANY subsequent boot after the hard disk boot -- FOR NOW!!
  1935. ;
  1936.  
  1937. stopall:
  1938.     move.b    #$100-$20,d7    ; prevent any other unit from booting
  1939.     rts            ; return to TOS ROMs
  1940.  
  1941. rootpath:
  1942.     dc.b    '\\',0
  1943. msg_bl:
  1944.     dc.b    'BOOTLOADED',13,10,0
  1945. msg_nbl:
  1946.     dc.b    'NOT Bootloaded',13,10,0
  1947. .even
  1948.  
  1949.  
  1950. ;+
  1951. ; list_init - Initialize a GEMDOS buffer list (BCBs are contiguous)
  1952. ;
  1953. ; Passed:
  1954. ;     a0.l = head of buffer list            (not changed)
  1955. ;    d0.l = size of each BCB (including data block)    (not changed)
  1956. ;    d1.w = count
  1957. ;         = number of buffers to be installed to the list - 1
  1958. ;
  1959. ; Uses:
  1960. ;    d1, a1
  1961. ;-
  1962. list_init:
  1963.     move.l    a0,-(sp)    ; save head of buffer list
  1964. lin0:    movea.l    a0,a1        ; a1 -> next BCB
  1965.     adda.l    d0,a1        ;    -> curr BCB + size of BCB
  1966.     move.l    a1,(a0)        ; b_link -> next BCB
  1967.     move.w    #-1,4(a0)    ; b_neg1 = -1
  1968.     adda.w    #BCBLEN,a0    ; a0 -> BCB data block
  1969.     move.l    a0,-4(a0)    ; b_bufr -> b_space
  1970.     movea.l    a1,a0
  1971.     dbra    d1,lin0
  1972.     suba.l    d0,a0        ; a0 -> last BCB
  1973.     clr.l    (a0)        ; lastBCB.b_link = NULL
  1974.     move.l    (sp)+,a0    ; restore head of buffer list
  1975.     rts
  1976.  
  1977.  
  1978. ;+
  1979. ; chklstmem - check if enough memory is allocated to replace GEMDOS
  1980. ;        buffer lists
  1981. ;
  1982. ; Returns:
  1983. ;    d0.l = size of each BCB (including data block)
  1984. ;         or -1 if not enough memory is allocated
  1985. ;    d1.l = new amount of memory to be kept if enough is allocated
  1986. ;
  1987. ; Uses:
  1988. ;    d0, d1
  1989. ;-
  1990. chklstmem:
  1991.     moveq    #BCBLEN,d0    ; d0.l = size of each BCB (inc. data block)
  1992.     add.w    maxssz,d0    ;      = BCB header len + data block size
  1993.     move.l    d0,d1        ; d1.l = d0.l * 4 
  1994.     lsl.l    #2,d1        ;      = total size of buffer lists
  1995.     add.l    tokeep,d1    ; d1.l = size needed
  1996.     cmp.l    memalloc,d1    ; enough memory allocated?
  1997.     bls.s    chk0        ; if so return
  1998.     moveq    #-1,d0        ; else return error
  1999. chk0:    rts
  2000.  
  2001.  
  2002. ;
  2003. ;+
  2004. ; critic - call up the critical error handler.
  2005. ;
  2006. ; Passed:
  2007. ;    d0.w = error code
  2008. ;    d1.w = drive # excluding A: and B:
  2009. ;
  2010. ; Uses:
  2011. ;    d0, d1, a0
  2012. ;
  2013. ; Returns:
  2014. ;    d0.l = whatever returned by the critical handler
  2015. ;        (magic RETRY code or something)
  2016. ;-
  2017. critic:    addq.w    #2,d1            ; drive # including A: and B:
  2018.     move.w    d1,-(sp)        ; drive #
  2019.     move.w    d0,-(sp)        ; error code
  2020.     movea.l    etv_critic,a0        ; a0 = address of error handler
  2021.     jsr    (a0)            ; critic_handler(error, drive)
  2022.     addq.l    #4,sp            ; clean up stack
  2023.     rts                ; return
  2024.  
  2025.  
  2026. ;+
  2027. ; errcode - find error code for previous Check Condition Status
  2028. ;
  2029. ; Assumed:
  2030. ;    cpun = current physical unit number
  2031. ;
  2032. ; Returns:
  2033. ;    d0.b = error code    (aka additional sense code)
  2034. ;
  2035. ; Sep-13-1989    ml.    For non-extended request sense, ask for 0 byte.
  2036. ;            (0 is default to return 4 bytes.)
  2037. ;-
  2038.     .globl    errcode
  2039. errcode:
  2040.     moveq    #22,d1            ; assume requesting extended sense
  2041.     move.w    cpun,d0            ; d0 = physical unit number
  2042.     btst    #3,d0            ; a SCSI unit?
  2043.     bne.s    err0            ; if so, ready to request
  2044.     andi.w    #07,d0            ; else mask off other flags
  2045.     btst.b    d0,embscsi        ; an embedded SCSI unit using ACSI?
  2046.     bne.s    err0            ; if so, request extended sense
  2047.     moveq    #0,d1            ; else request non-extended sense
  2048. err0:    lea    sendata,a0        ; a0 -> sense data buffer
  2049.     movem.l    d1/a0,-(sp)        ; save data len and buffer address
  2050.     move.l    a0,-(sp)        ; sense data buffer
  2051.     move.w    d1,-(sp)        ; data length (in bytes)
  2052.     move.w    d0,-(sp)        ; physical unit number
  2053.     bsr    _rqsense        ; find out error code
  2054.     addq.l    #8,sp            ; clean up stack
  2055.     movem.l    (sp)+,d1/a0        ; restore d1 and a0
  2056.     tst.w    d0            ; successful?
  2057.     beq.s    err1            ; if not, return
  2058.     moveq    #-1,d0            ; error occurred
  2059.     rts
  2060. err1:    cmpi.w    #4,d1            ; extended or non-extended?
  2061.     bgt.s    err2            ; if extended, go get code
  2062.     move.b    (a0),d0            ; else byte 0 = error code
  2063.     andi.b    #$7f,d0            ; mask off valid bit
  2064.     rts
  2065. err2:    move.b    12(a0),d0        ; else byte 12 = error code
  2066.     rts
  2067.  
  2068.  
  2069. ;
  2070. ;+
  2071. ; OS Pool Expansion
  2072. ;-
  2073.  
  2074. .if ospool
  2075. ;+
  2076. ;  Wire more pool into various ROM releases.
  2077. ;
  2078. ;    Passed:    nothing
  2079. ;    Returns:    D0 = #bytes extra used
  2080. ;-
  2081. pool_install:
  2082.     move.l    _sysbase,a3        ; a3 -> base of OS
  2083.  
  2084. ; make sure we're in ROM,
  2085. ; then get address of RAM location to patch:
  2086.  
  2087.     cmp.l    #$800000,a3        ; better be ROM
  2088.     blt    notrom
  2089.     lea    pool_tab(pc),a0        ; a0 -> table to match
  2090. pi_lp:    move.l    (a0)+,d1        ; d1 = date to match
  2091.     beq    badrom            ; (forget it, end of list)
  2092.     move.l    (a0)+,a2        ; a2 -> _root address for that date
  2093.     cmp.l    $18(a3),d1        ; match dates?
  2094.     bne.s    pi_lp            ; (no -- try again)
  2095.  
  2096.     move.w    numchunks,d0        ; d0 = amount of BSS to be used
  2097.     mulu    #chunksiz,d0        ;    = # chunks * size of a chunk
  2098.     move.l    d0,d1            ; d1 = total memory needed
  2099.     add.l    tokeep,d1        ;    = already keeping + extra OS pool
  2100.     cmp.l    memalloc,d1        ; enough is allocated?
  2101.     bgt.s    bdrom2            ; if not, don't add any
  2102.                     ; else install more OS pool
  2103.     movea.l    #i_sasi+2,a0        ; a0 -> base of first buffer
  2104.     adda.l    tokeep,a0        ;    = start of file + already keeping
  2105.     move.l    a0,-(sp)        ; save base of first buffer
  2106.     move.w    numchunks,d1        ; d0 = count-1
  2107.     subq.w    #1,d1
  2108. pin_1:    lea    chunksiz(a0),a1        ; a1 -> next buffer
  2109.     move.l    a1,(a0)            ; buffer -> next one
  2110.     move.w    #chunkno,-2(a0)        ; install chunksiz
  2111.     move.l    a1,a0            ; a0 -> next buffer
  2112.     dbra    d1,pin_1        ; (do some more)
  2113.  
  2114.     sub.w    #chunksiz,a0        ; a0 -> last block
  2115.     move.l    chunkno*4(a2),(a0)    ; last block -> first in root
  2116.     move.l    (sp)+,chunkno*4(a2)     ; root -> first of ours
  2117.     rts                ; return OK
  2118.  
  2119. ;+
  2120. ;  Print warning messages
  2121. ;  about bogus versions of the
  2122. ;  operating system.  Assume that
  2123. ;  every OS past 1-May-1986 has the
  2124. ;  pool fix installed.
  2125. ;
  2126. ;-
  2127. ok_date    =    %0000110010100001    ; 1-May-1986
  2128. notrom:    lea    m_notrom(pc),a0        ; ram-based system (5/29!)
  2129.     bra.s    bdrom1
  2130. badrom:    lea    m_badrom(pc),a0        ; illegal ROM system
  2131. bdrom1:    cmp.w    #ok_date,$1e(a3)    ; if ok_date <= os_dosdate(a3) 
  2132.     bcc    bdrom2            ; then don't print anything
  2133.  
  2134.     move.l    a0,-(sp)        ; print nasty message
  2135.     move.w    #9,-(sp)
  2136.     trap    #1
  2137.     addq.l    #6,sp
  2138.  
  2139. ; print msg and wait for RETURN
  2140.     pea    keymsg(pc)
  2141.     move.w    #9,-(sp)
  2142.     trap    #1
  2143.     addq.l    #6,sp
  2144.  
  2145. bdrom3:    move.w    #2,-(sp)        ; wait for [RETURN]
  2146.     move.w    #2,-(sp)
  2147.     trap    #13
  2148.     addq.l    #4,sp
  2149.     cmp.w    #13,d0
  2150.     bne    bdrom3
  2151.  
  2152. bdrom2:    moveq    #0,d0            ; 0 extra bytes used
  2153.     rts
  2154.  
  2155. keymsg:    dc.b    'Hard disk driver not loaded; hit RETURN',13,10
  2156.     dc.b    'key to continue:',13,10
  2157.     dc.b    0
  2158.  
  2159. m_notrom:
  2160.     dc.b    '*** WARNING ***',13,10,7
  2161.     dc.b    'This hard disk driver may not work with',13,10,7
  2162.     dc.b    'a disk-based version of TOS; files on',13,10,7
  2163.     dc.b    'your hard disk may be damaged.',13,10,7
  2164.     dc.b    13,10,7
  2165.     dc.b    0
  2166.  
  2167. m_badrom:
  2168.     dc.b    '*** WARNING ***',13,10,7
  2169.     dc.b    'You are using an unofficial ROM release',13,10,7
  2170.     dc.b    'of the operating system.  This driver',13,10,7
  2171.     dc.b    'may not work correctly with it.  Files',13,10,7
  2172.     dc.b    'on your hard disk may be damaged.',13,10,7
  2173.     dc.b    13,10,7
  2174.     dc.b    0
  2175.     even
  2176.  
  2177.  
  2178. ;+
  2179. ;  Table of ROM release dates / _root addresses
  2180. ;  update these for new ROM releases that need the patch.
  2181. ;
  2182. ;-
  2183. pool_tab:
  2184.     dc.l    $11201985,$56fa        ; USA and UK, 20-Nov-1985
  2185.     dc.l    $02061986,$56fa        ; Germany, 6-Feb-1986
  2186.     dc.l    $04241986,$56fa        ; France, 24-Apr-1986
  2187.     dc.l    0            ; end of list
  2188.  
  2189. .endif
  2190.  
  2191.  
  2192.